Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15:Update
ruby2.5.36162
suse.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File suse.patch of Package ruby2.5.36162
diff --git a/Makefile.in b/Makefile.in index 25075f5900..515cac832b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -233,7 +233,7 @@ miniruby$(EXEEXT): $(PROGRAM): @$(RM) $@ $(ECHO) linking $@ - $(Q) $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(MAINLIBS) $(LIBS) $(EXTLIBS) $(OUTFLAG)$@ + $(Q) $(PURIFY) $(CC) -pie $(LDFLAGS) $(XLDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(MAINLIBS) $(LIBS) $(EXTLIBS) $(OUTFLAG)$@ $(Q) $(POSTLINK) # We must `rm' the library each time this rule is invoked because "updating" a diff --git a/ext/bigdecimal/bigdecimal.gemspec b/ext/bigdecimal/bigdecimal.gemspec index c8c90870ea..9cf22f7e0a 100644 --- a/ext/bigdecimal/bigdecimal.gemspec +++ b/ext/bigdecimal/bigdecimal.gemspec @@ -6,6 +6,7 @@ s.name = "bigdecimal" s.version = bigdecimal_version s.authors = ["Kenta Murata", "Zachary Scott", "Shigeo Kobayashi"] + s.date = RUBY_RELEASE_DATE s.email = ["mrkn@mrkn.jp"] s.summary = "Arbitrary-precision decimal floating-point number library." diff --git a/ext/cgi/escape/escape.c b/ext/cgi/escape/escape.c index ced1b182eb..578d651dc1 100644 --- a/ext/cgi/escape/escape.c +++ b/ext/cgi/escape/escape.c @@ -11,6 +11,21 @@ RUBY_EXTERN const signed char ruby_digit36_to_number_table[]; static VALUE rb_cCGI, rb_mUtil, rb_mEscape; static ID id_accept_charset; +#define HTML_ESCAPE_MAX_LEN 6 + +static const struct { + uint8_t len; + char str[HTML_ESCAPE_MAX_LEN+1]; +} html_escape_table[UCHAR_MAX+1] = { +#define HTML_ESCAPE(c, str) [c] = {rb_strlen_lit(str), str} + HTML_ESCAPE('\'', "'"), + HTML_ESCAPE('&', "&"), + HTML_ESCAPE('"', """), + HTML_ESCAPE('<', "<"), + HTML_ESCAPE('>', ">"), +#undef HTML_ESCAPE +}; + static void html_escaped_cat(VALUE str, char c) { @@ -44,40 +59,35 @@ preserve_original_state(VALUE orig, VALUE dest) static VALUE optimized_escape_html(VALUE str) { - long i, len, beg = 0; - VALUE dest = 0; - const char *cstr; - - len = RSTRING_LEN(str); - cstr = RSTRING_PTR(str); - - for (i = 0; i < len; i++) { - switch (cstr[i]) { - case '\'': - case '&': - case '"': - case '<': - case '>': - if (!dest) { - dest = rb_str_buf_new(len); - } - - rb_str_cat(dest, cstr + beg, i - beg); - beg = i + 1; - - html_escaped_cat(dest, cstr[i]); - break; - } + VALUE vbuf; + typedef char escape_buf[HTML_ESCAPE_MAX_LEN]; + char *buf = *ALLOCV_N(escape_buf, vbuf, RSTRING_LEN(str)); + const char *cstr = RSTRING_PTR(str); + const char *end = cstr + RSTRING_LEN(str); + + char *dest = buf; + while (cstr < end) { + const unsigned char c = *cstr++; + uint8_t len = html_escape_table[c].len; + if (len) { + memcpy(dest, html_escape_table[c].str, len); + dest += len; + } + else { + *dest++ = c; + } } - if (dest) { - rb_str_cat(dest, cstr + beg, len - beg); - preserve_original_state(str, dest); - return dest; + VALUE escaped; + if (RSTRING_LEN(str) < (dest - buf)) { + escaped = rb_str_new(buf, dest - buf); + preserve_original_state(str, escaped); } else { - return rb_str_dup(str); + escaped = rb_str_dup(str); } + ALLOCV_END(vbuf); + return escaped; } static VALUE diff --git a/ext/date/date_core.c b/ext/date/date_core.c index c250633426..1734ec0349 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -51,6 +51,9 @@ static double positive_inf, negative_inf; #define f_add3(x,y,z) f_add(f_add(x, y), z) #define f_sub3(x,y,z) f_sub(f_sub(x, y), z) +static VALUE date_initialize(int argc, VALUE *argv, VALUE self); +static VALUE datetime_initialize(int argc, VALUE *argv, VALUE self); + inline static int f_cmp(VALUE x, VALUE y) { @@ -94,7 +97,7 @@ f_ge_p(VALUE x, VALUE y) { if (FIXNUM_P(x) && FIXNUM_P(y)) return f_boolcast(FIX2LONG(x) >= FIX2LONG(y)); - return rb_funcall(x, rb_intern(">="), 1, y); + return rb_funcall(x, id_ge_p, 1, y); } inline static VALUE @@ -102,7 +105,7 @@ f_eqeq_p(VALUE x, VALUE y) { if (FIXNUM_P(x) && FIXNUM_P(y)) return f_boolcast(FIX2LONG(x) == FIX2LONG(y)); - return rb_funcall(x, rb_intern("=="), 1, y); + return rb_funcall(x, id_eqeq_p, 1, y); } inline static VALUE @@ -236,11 +239,8 @@ f_negative_p(VALUE x) struct SimpleDateData { unsigned flags; - VALUE nth; /* not always canonicalized */ int jd; /* as utc */ - /* df is zero */ - /* sf is zero */ - /* of is zero */ + VALUE nth; /* not always canonicalized */ date_sg_t sg; /* 2298874..2426355 or -/+oo -- at most 22 bits */ /* decoded as utc=local */ int year; /* truncated */ @@ -259,11 +259,8 @@ struct SimpleDateData struct ComplexDateData { unsigned flags; - VALUE nth; /* not always canonicalized */ int jd; /* as utc */ - int df; /* as utc, in secs */ - VALUE sf; /* in nano secs */ - int of; /* in secs */ + VALUE nth; /* not always canonicalized */ date_sg_t sg; /* 2298874..2426355 or -/+oo -- at most 22 bits */ /* decoded as local */ int year; /* truncated */ @@ -277,6 +274,9 @@ struct ComplexDateData /* packed civil */ unsigned pc; #endif + int df; /* as utc, in secs */ + int of; /* in secs */ + VALUE sf; /* in nano secs */ }; union DateData { @@ -315,31 +315,31 @@ canon(VALUE x) #ifndef USE_PACK #define set_to_simple(obj, x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \ -{\ +do {\ RB_OBJ_WRITE((obj), &(x)->nth, canon(_nth)); \ (x)->jd = _jd;\ (x)->sg = (date_sg_t)(_sg);\ (x)->year = _year;\ (x)->mon = _mon;\ (x)->mday = _mday;\ - (x)->flags = _flags;\ -} + (x)->flags = (_flags) & ~COMPLEX_DAT;\ +} while (0) #else #define set_to_simple(obj, x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \ -{\ +do {\ RB_OBJ_WRITE((obj), &(x)->nth, canon(_nth)); \ (x)->jd = _jd;\ (x)->sg = (date_sg_t)(_sg);\ (x)->year = _year;\ (x)->pc = PACK2(_mon, _mday);\ - (x)->flags = _flags;\ -} + (x)->flags = (_flags) & ~COMPLEX_DAT;\ +} while (0) #endif #ifndef USE_PACK #define set_to_complex(obj, x, _nth, _jd ,_df, _sf, _of, _sg,\ _year, _mon, _mday, _hour, _min, _sec, _flags) \ -{\ +do {\ RB_OBJ_WRITE((obj), &(x)->nth, canon(_nth));\ (x)->jd = _jd;\ (x)->df = _df;\ @@ -352,12 +352,12 @@ _year, _mon, _mday, _hour, _min, _sec, _flags) \ (x)->hour = _hour;\ (x)->min = _min;\ (x)->sec = _sec;\ - (x)->flags = _flags;\ -} + (x)->flags = (_flags) | COMPLEX_DAT;\ +} while (0) #else #define set_to_complex(obj, x, _nth, _jd ,_df, _sf, _of, _sg,\ _year, _mon, _mday, _hour, _min, _sec, _flags) \ -{\ +do {\ RB_OBJ_WRITE((obj), &(x)->nth, canon(_nth));\ (x)->jd = _jd;\ (x)->df = _df;\ @@ -366,13 +366,13 @@ _year, _mon, _mday, _hour, _min, _sec, _flags) \ (x)->sg = (date_sg_t)(_sg);\ (x)->year = _year;\ (x)->pc = PACK5(_mon, _mday, _hour, _min, _sec);\ - (x)->flags = _flags;\ -} + (x)->flags = (_flags) | COMPLEX_DAT;\ +} while (0) #endif #ifndef USE_PACK #define copy_simple_to_complex(obj, x, y) \ -{\ +do {\ RB_OBJ_WRITE((obj), &(x)->nth, (y)->nth);\ (x)->jd = (y)->jd;\ (x)->df = 0;\ @@ -386,10 +386,10 @@ _year, _mon, _mday, _hour, _min, _sec, _flags) \ (x)->min = 0;\ (x)->sec = 0;\ (x)->flags = (y)->flags;\ -} +} while (0) #else #define copy_simple_to_complex(obj, x, y) \ -{\ +do {\ RB_OBJ_WRITE((obj), &(x)->nth, (y)->nth);\ (x)->jd = (y)->jd;\ (x)->df = 0;\ @@ -399,12 +399,12 @@ _year, _mon, _mday, _hour, _min, _sec, _flags) \ (x)->year = (y)->year;\ (x)->pc = PACK5(EX_MON((y)->pc), EX_MDAY((y)->pc), 0, 0, 0);\ (x)->flags = (y)->flags;\ -} +} while (0) #endif #ifndef USE_PACK #define copy_complex_to_simple(obj, x, y) \ -{\ +do {\ RB_OBJ_WRITE((obj), &(x)->nth, (y)->nth);\ (x)->jd = (y)->jd;\ (x)->sg = (date_sg_t)((y)->sg);\ @@ -412,17 +412,17 @@ _year, _mon, _mday, _hour, _min, _sec, _flags) \ (x)->mon = (y)->mon;\ (x)->mday = (y)->mday;\ (x)->flags = (y)->flags;\ -} +} while (0) #else #define copy_complex_to_simple(obj, x, y) \ -{\ +do {\ RB_OBJ_WRITE((obj), &(x)->nth, (y)->nth);\ (x)->jd = (y)->jd;\ (x)->sg = (date_sg_t)((y)->sg);\ (x)->year = (y)->year;\ (x)->pc = PACK2(EX_MON((y)->pc), EX_MDAY((y)->pc));\ (x)->flags = (y)->flags;\ -} +} while (0) #endif /* base */ @@ -1109,7 +1109,7 @@ m_virtual_sg(union DateData *x) } #define canonicalize_jd(_nth, _jd) \ -{\ +do {\ if (_jd < 0) {\ _nth = f_sub(_nth, INT2FIX(1));\ _jd += CM_PERIOD;\ @@ -1118,7 +1118,7 @@ m_virtual_sg(union DateData *x) _nth = f_add(_nth, INT2FIX(1));\ _jd -= CM_PERIOD;\ }\ -} +} while (0) inline static void canonicalize_s_jd(VALUE obj, union DateData *x) @@ -1928,13 +1928,13 @@ m_sec(union DateData *x) } #define decode_offset(of,s,h,m)\ -{\ +do {\ int a;\ s = (of < 0) ? '-' : '+';\ a = (of < 0) ? -of : of;\ h = a / HOUR_IN_SECONDS;\ m = a % HOUR_IN_SECONDS / MINUTE_IN_SECONDS;\ -} +} while (0) static VALUE of2str(int of) @@ -2333,6 +2333,9 @@ VALUE date_zone_to_diff(VALUE); static int offset_to_sec(VALUE vof, int *rof) { + int try_rational = 1; + + again: switch (TYPE(vof)) { case T_FIXNUM: { @@ -2359,10 +2362,11 @@ offset_to_sec(VALUE vof, int *rof) default: expect_numeric(vof); vof = f_to_r(vof); -#ifdef CANONICALIZATION_FOR_MATHN - if (!k_rational_p(vof)) - return offset_to_sec(vof, rof); -#endif + if (!k_rational_p(vof)) { + if (!try_rational) Check_Type(vof, T_RATIONAL); + try_rational = 0; + goto again; + } /* fall through */ case T_RATIONAL: { @@ -2371,17 +2375,10 @@ offset_to_sec(VALUE vof, int *rof) vs = day_to_sec(vof); -#ifdef CANONICALIZATION_FOR_MATHN if (!k_rational_p(vs)) { - if (!FIXNUM_P(vs)) - return 0; - n = FIX2LONG(vs); - if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) - return 0; - *rof = (int)n; - return 1; + vn = vs; + goto rounded; } -#endif vn = rb_rational_num(vs); vd = rb_rational_den(vs); @@ -2391,6 +2388,7 @@ offset_to_sec(VALUE vof, int *rof) vn = f_round(vs); if (!f_eqeq_p(vn, vs)) rb_warning("fraction of offset is ignored"); + rounded: if (!FIXNUM_P(vn)) return 0; n = FIX2LONG(vn); @@ -2420,12 +2418,12 @@ offset_to_sec(VALUE vof, int *rof) /* date */ #define valid_sg(sg) \ -{\ +do {\ if (!c_valid_start_p(sg)) {\ sg = 0;\ rb_warning("invalid start is ignored");\ }\ -} +} while (0) static VALUE valid_jd_sub(int argc, VALUE *argv, VALUE klass, int need_jd) @@ -2968,7 +2966,7 @@ d_simple_new_internal(VALUE klass, obj = TypedData_Make_Struct(klass, struct SimpleDateData, &d_lite_type, dat); - set_to_simple(obj, dat, nth, jd, sg, y, m, d, flags & ~COMPLEX_DAT); + set_to_simple(obj, dat, nth, jd, sg, y, m, d, flags); assert(have_jd_p(dat) || have_civil_p(dat)); @@ -2990,7 +2988,7 @@ d_complex_new_internal(VALUE klass, obj = TypedData_Make_Struct(klass, struct ComplexDateData, &d_lite_type, dat); set_to_complex(obj, dat, nth, jd, df, sf, of, sg, - y, m, d, h, min, s, flags | COMPLEX_DAT); + y, m, d, h, min, s, flags); assert(have_jd_p(dat) || have_civil_p(dat)); assert(have_df_p(dat) || have_time_p(dat)); @@ -3207,47 +3205,47 @@ s_trunc(VALUE s, VALUE *fr) } #define num2num_with_frac(s,n) \ -{\ +do {\ s = s##_trunc(v##s, &fr);\ if (f_nonzero_p(fr)) {\ if (argc > n)\ rb_raise(rb_eArgError, "invalid fraction");\ fr2 = fr;\ }\ -} +} while (0) #define num2int_with_frac(s,n) \ -{\ +do {\ s = NUM2INT(s##_trunc(v##s, &fr));\ if (f_nonzero_p(fr)) {\ if (argc > n)\ rb_raise(rb_eArgError, "invalid fraction");\ fr2 = fr;\ }\ -} +} while (0) #define canon24oc() \ -{\ +do {\ if (rh == 24) {\ rh = 0;\ fr2 = f_add(fr2, INT2FIX(1));\ }\ -} +} while (0) #define add_frac() \ -{\ +do {\ if (f_nonzero_p(fr2))\ ret = d_lite_plus(ret, fr2);\ -} +} while (0) #define val2sg(vsg,dsg) \ -{\ +do {\ dsg = NUM2DBL(vsg);\ if (!c_valid_start_p(dsg)) {\ dsg = DEFAULT_SG;\ rb_warning("invalid start is ignored");\ }\ -} +} while (0) static VALUE d_lite_plus(VALUE, VALUE); @@ -3384,10 +3382,21 @@ date_s_ordinal(int argc, VALUE *argv, VALUE klass) */ static VALUE date_s_civil(int argc, VALUE *argv, VALUE klass) +{ + return date_initialize(argc, argv, d_lite_s_alloc_simple(klass)); +} + +static VALUE +date_initialize(int argc, VALUE *argv, VALUE self) { VALUE vy, vm, vd, vsg, y, fr, fr2, ret; int m, d; double sg; + struct SimpleDateData *dat = rb_check_typeddata(self, &d_lite_type); + + if (!simple_dat_p(dat)) { + rb_raise(rb_eTypeError, "Date expected"); + } rb_scan_args(argc, argv, "04", &vy, &vm, &vd, &vsg); @@ -3417,11 +3426,7 @@ date_s_civil(int argc, VALUE *argv, VALUE klass) &rm, &rd)) rb_raise(rb_eArgError, "invalid date"); - ret = d_simple_new_internal(klass, - nth, 0, - sg, - ry, rm, rd, - HAVE_CIVIL); + set_to_simple(self, dat, nth, 0, sg, ry, rm, rd, HAVE_CIVIL); } else { VALUE nth; @@ -3433,12 +3438,9 @@ date_s_civil(int argc, VALUE *argv, VALUE klass) &ns)) rb_raise(rb_eArgError, "invalid date"); - ret = d_simple_new_internal(klass, - nth, rjd, - sg, - ry, rm, rd, - HAVE_JD | HAVE_CIVIL); + set_to_simple(self, dat, nth, rjd, sg, ry, rm, rd, HAVE_JD | HAVE_CIVIL); } + ret = self; add_frac(); return ret; } @@ -3679,9 +3681,11 @@ date_s_today(int argc, VALUE *argv, VALUE klass) #define ref_hash0(k) rb_hash_aref(hash, k) #define del_hash0(k) rb_hash_delete(hash, k) -#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v) -#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k))) -#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k))) +#define sym(x) ID2SYM(rb_intern(x"")) + +#define set_hash(k,v) set_hash0(sym(k), v) +#define ref_hash(k) ref_hash0(sym(k)) +#define del_hash(k) del_hash0(sym(k)) static VALUE rt_rewrite_frags(VALUE hash) @@ -3718,8 +3722,6 @@ rt_rewrite_frags(VALUE hash) return hash; } -#define sym(x) ID2SYM(rb_intern(x)) - static VALUE d_lite_year(VALUE); static VALUE d_lite_wday(VALUE); static VALUE d_lite_jd(VALUE); @@ -4290,12 +4292,40 @@ date_s_strptime(int argc, VALUE *argv, VALUE klass) VALUE date__parse(VALUE str, VALUE comp); +static size_t +get_limit(VALUE opt) +{ + if (!NIL_P(opt)) { + VALUE limit = rb_hash_aref(opt, ID2SYM(rb_intern("limit"))); + if (NIL_P(limit)) return SIZE_MAX; + return NUM2SIZET(limit); + } + return 128; +} + +static void +check_limit(VALUE str, VALUE opt) +{ + if (NIL_P(str)) return; + if (SYMBOL_P(str)) str = rb_sym2str(str); + + StringValue(str); + size_t slen = RSTRING_LEN(str); + size_t limit = get_limit(opt); + if (slen > limit) { + rb_raise(rb_eArgError, + "string length (%"PRI_SIZE_PREFIX"u) exceeds the limit %"PRI_SIZE_PREFIX"u", slen, limit); + } +} + static VALUE date_s__parse_internal(int argc, VALUE *argv, VALUE klass) { - VALUE vstr, vcomp, hash; + VALUE vstr, vcomp, hash, opt; - rb_scan_args(argc, argv, "11", &vstr, &vcomp); + rb_scan_args(argc, argv, "11:", &vstr, &vcomp, &opt); + if (!NIL_P(opt)) argc--; + check_limit(vstr, opt); StringValue(vstr); if (!rb_enc_str_asciicompat_p(vstr)) rb_raise(rb_eArgError, @@ -4320,7 +4350,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Date._parse(string[, comp=true]) -> hash + * Date._parse(string[, comp=true], limit: 128) -> hash * * Parses the given representation of date and time, and returns a * hash of parsed elements. This method does not function as a @@ -4331,6 +4361,10 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass) * it full. * * Date._parse('2001-02-03') #=> {:year=>2001, :mon=>2, :mday=>3} + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE date_s__parse(int argc, VALUE *argv, VALUE klass) @@ -4340,7 +4374,7 @@ date_s__parse(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Date.parse(string='-4712-01-01'[, comp=true[, start=Date::ITALY]]) -> date + * Date.parse(string='-4712-01-01'[, comp=true[, start=Date::ITALY]], limit: 128) -> date * * Parses the given representation of date and time, and creates a * date object. This method does not function as a validator. @@ -4352,13 +4386,18 @@ date_s__parse(int argc, VALUE *argv, VALUE klass) * Date.parse('2001-02-03') #=> #<Date: 2001-02-03 ...> * Date.parse('20010203') #=> #<Date: 2001-02-03 ...> * Date.parse('3rd Feb 2001') #=> #<Date: 2001-02-03 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE date_s_parse(int argc, VALUE *argv, VALUE klass) { - VALUE str, comp, sg; + VALUE str, comp, sg, opt; - rb_scan_args(argc, argv, "03", &str, &comp, &sg); + rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -4370,11 +4409,12 @@ date_s_parse(int argc, VALUE *argv, VALUE klass) } { - VALUE argv2[2], hash; - - argv2[0] = str; - argv2[1] = comp; - hash = date_s__parse(2, argv2, klass); + int argc2 = 2; + VALUE argv2[3]; + argv2[0] = str; + argv2[1] = comp; + if (!NIL_P(opt)) argv2[argc2++] = opt; + VALUE hash = date_s__parse(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } @@ -4388,19 +4428,28 @@ VALUE date__jisx0301(VALUE); /* * call-seq: - * Date._iso8601(string) -> hash + * Date._iso8601(string, limit: 128) -> hash * * Returns a hash of parsed elements. + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE -date_s__iso8601(VALUE klass, VALUE str) +date_s__iso8601(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + check_limit(str, opt); + return date__iso8601(str); } /* * call-seq: - * Date.iso8601(string='-4712-01-01'[, start=Date::ITALY]) -> date + * Date.iso8601(string='-4712-01-01'[, start=Date::ITALY], limit: 128) -> date * * Creates a new Date object by parsing from a string according to * some typical ISO 8601 formats. @@ -4408,13 +4457,18 @@ date_s__iso8601(VALUE klass, VALUE str) * Date.iso8601('2001-02-03') #=> #<Date: 2001-02-03 ...> * Date.iso8601('20010203') #=> #<Date: 2001-02-03 ...> * Date.iso8601('2001-W05-6') #=> #<Date: 2001-02-03 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE date_s_iso8601(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -4424,38 +4478,56 @@ date_s_iso8601(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__iso8601(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + VALUE hash = date_s__iso8601(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._rfc3339(string) -> hash + * Date._rfc3339(string, limit: 128) -> hash * * Returns a hash of parsed elements. + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE -date_s__rfc3339(VALUE klass, VALUE str) +date_s__rfc3339(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + check_limit(str, opt); + return date__rfc3339(str); } /* * call-seq: - * Date.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> date + * Date.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> date * * Creates a new Date object by parsing from a string according to * some typical RFC 3339 formats. * * Date.rfc3339('2001-02-03T04:05:06+07:00') #=> #<Date: 2001-02-03 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE date_s_rfc3339(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -4465,38 +4537,56 @@ date_s_rfc3339(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__rfc3339(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + VALUE hash = date_s__rfc3339(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._xmlschema(string) -> hash + * Date._xmlschema(string, limit: 128) -> hash * * Returns a hash of parsed elements. + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE -date_s__xmlschema(VALUE klass, VALUE str) +date_s__xmlschema(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + check_limit(str, opt); + return date__xmlschema(str); } /* * call-seq: - * Date.xmlschema(string='-4712-01-01'[, start=Date::ITALY]) -> date + * Date.xmlschema(string='-4712-01-01'[, start=Date::ITALY], limit: 128) -> date * * Creates a new Date object by parsing from a string according to * some typical XML Schema formats. * * Date.xmlschema('2001-02-03') #=> #<Date: 2001-02-03 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE date_s_xmlschema(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -4506,41 +4596,58 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__xmlschema(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + VALUE hash = date_s__xmlschema(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._rfc2822(string) -> hash - * Date._rfc822(string) -> hash + * Date._rfc2822(string, limit: 128) -> hash + * Date._rfc822(string, limit: 128) -> hash * * Returns a hash of parsed elements. + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE -date_s__rfc2822(VALUE klass, VALUE str) +date_s__rfc2822(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + check_limit(str, opt); + return date__rfc2822(str); } /* * call-seq: - * Date.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY]) -> date - * Date.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY]) -> date + * Date.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> date + * Date.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> date * * Creates a new Date object by parsing from a string according to * some typical RFC 2822 formats. * * Date.rfc2822('Sat, 3 Feb 2001 00:00:00 +0000') * #=> #<Date: 2001-02-03 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE date_s_rfc2822(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: @@ -4550,39 +4657,56 @@ date_s_rfc2822(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__rfc2822(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + VALUE hash = date_s__rfc2822(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._httpdate(string) -> hash + * Date._httpdate(string, limit: 128) -> hash * * Returns a hash of parsed elements. + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE -date_s__httpdate(VALUE klass, VALUE str) +date_s__httpdate(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + check_limit(str, opt); + return date__httpdate(str); } /* * call-seq: - * Date.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=Date::ITALY]) -> date + * Date.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=Date::ITALY], limit: 128) -> date * * Creates a new Date object by parsing from a string according to * some RFC 2616 format. * * Date.httpdate('Sat, 03 Feb 2001 00:00:00 GMT') * #=> #<Date: 2001-02-03 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE date_s_httpdate(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: @@ -4592,38 +4716,60 @@ date_s_httpdate(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__httpdate(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + VALUE hash = date_s__httpdate(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._jisx0301(string) -> hash + * Date._jisx0301(string, limit: 128) -> hash * * Returns a hash of parsed elements. + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE -date_s__jisx0301(VALUE klass, VALUE str) +date_s__jisx0301(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + check_limit(str, opt); + return date__jisx0301(str); } /* * call-seq: - * Date.jisx0301(string='-4712-01-01'[, start=Date::ITALY]) -> date + * Date.jisx0301(string='-4712-01-01'[, start=Date::ITALY], limit: 128) -> date * * Creates a new Date object by parsing from a string according to * some typical JIS X 0301 formats. * * Date.jisx0301('H13.02.03') #=> #<Date: 2001-02-03 ...> + * + * For no-era year, legacy format, Heisei is assumed. + * + * Date.jisx0301('13.02.03') #=> #<Date: 2001-02-03 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE date_s_jisx0301(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -4633,7 +4779,11 @@ date_s_jisx0301(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__jisx0301(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + VALUE hash = date_s__jisx0301(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } @@ -4691,14 +4841,14 @@ dup_obj_as_complex(VALUE self) } #define val2off(vof,iof) \ -{\ +do {\ if (!offset_to_sec(vof, &iof)) {\ iof = 0;\ rb_warning("invalid offset is ignored");\ }\ -} +} while (0) -#ifndef NDEBUG +#if 0 static VALUE d_lite_initialize(int argc, VALUE *argv, VALUE self) { @@ -4751,7 +4901,7 @@ d_lite_initialize(int argc, VALUE *argv, VALUE self) "cannot load complex into simple"); set_to_complex(self, &dat->c, nth, rjd, df, sf, of, sg, - 0, 0, 0, 0, 0, 0, HAVE_JD | HAVE_DF | COMPLEX_DAT); + 0, 0, 0, 0, 0, 0, HAVE_JD | HAVE_DF); } } return self; @@ -4770,8 +4920,28 @@ d_lite_initialize_copy(VALUE copy, VALUE date) { get_d2(copy, date); if (simple_dat_p(bdat)) { - adat->s = bdat->s; - adat->s.flags &= ~COMPLEX_DAT; + if (simple_dat_p(adat)) { + adat->s = bdat->s; + } + else { + adat->c.flags = bdat->s.flags | COMPLEX_DAT; + adat->c.nth = bdat->s.nth; + adat->c.jd = bdat->s.jd; + adat->c.df = 0; + adat->c.sf = INT2FIX(0); + adat->c.of = 0; + adat->c.sg = bdat->s.sg; + adat->c.year = bdat->s.year; +#ifndef USE_PACK + adat->c.mon = bdat->s.mon; + adat->c.mday = bdat->s.mday; + adat->c.hour = bdat->s.hour; + adat->c.min = bdat->s.min; + adat->c.sec = bdat->s.sec; +#else + adat->c.pc = bdat->s.pc; +#endif + } } else { if (!complex_dat_p(adat)) @@ -4779,7 +4949,6 @@ d_lite_initialize_copy(VALUE copy, VALUE date) "cannot load complex into simple"); adat->c = bdat->c; - adat->c.flags |= COMPLEX_DAT; } } return copy; @@ -5513,8 +5682,10 @@ d_lite_new_offset(int argc, VALUE *argv, VALUE self) static VALUE d_lite_plus(VALUE self, VALUE other) { + int try_rational = 1; get_d1(self); + again: switch (TYPE(other)) { case T_FIXNUM: { @@ -5724,18 +5895,21 @@ d_lite_plus(VALUE self, VALUE other) default: expect_numeric(other); other = f_to_r(other); -#ifdef CANONICALIZATION_FOR_MATHN - if (!k_rational_p(other)) - return d_lite_plus(self, other); -#endif + if (!k_rational_p(other)) { + if (!try_rational) Check_Type(other, T_RATIONAL); + try_rational = 0; + goto again; + } /* fall through */ case T_RATIONAL: { VALUE nth, sf, t; int jd, df, s; - if (wholenum_p(other)) - return d_lite_plus(self, rb_rational_num(other)); + if (wholenum_p(other)) { + other = rb_rational_num(other); + goto again; + } if (f_positive_p(other)) s = +1; @@ -6242,7 +6416,7 @@ cmp_gen(VALUE self, VALUE other) return INT2FIX(f_cmp(m_ajd(dat), other)); else if (k_date_p(other)) return INT2FIX(f_cmp(m_ajd(dat), f_ajd(other))); - return rb_num_coerce_cmp(self, other, rb_intern("<=>")); + return rb_num_coerce_cmp(self, other, id_cmp); } static VALUE @@ -6371,7 +6545,7 @@ equal_gen(VALUE self, VALUE other) return f_eqeq_p(m_real_local_jd(dat), other); else if (k_date_p(other)) return f_eqeq_p(m_real_local_jd(dat), f_jd(other)); - return rb_num_coerce_cmp(self, other, rb_intern("==")); + return rb_num_coerce_cmp(self, other, id_eqeq_p); } /* @@ -6469,7 +6643,7 @@ d_lite_to_s(VALUE self) static VALUE mk_inspect_raw(union DateData *x, VALUE klass) { - char flags[5]; + char flags[6]; flags[0] = (x->flags & COMPLEX_DAT) ? 'C' : 'S'; flags[1] = (x->flags & HAVE_JD) ? 'j' : '-'; @@ -6635,7 +6809,9 @@ tmx_m_of(union DateData *x) static char * tmx_m_zone(union DateData *x) { - return RSTRING_PTR(m_zone(x)); + VALUE zone = m_zone(x); + /* TODO: fix potential dangling pointer */ + return RSTRING_PTR(zone); } static const struct tmx_funcs tmx_funcs = { @@ -6785,7 +6961,7 @@ date_strftime_internal(int argc, VALUE *argv, VALUE self, * * %M - Minute of the hour (00..59) * - * %S - Second of the minute (00..59) + * %S - Second of the minute (00..60) * * %L - Millisecond of the second (000..999) * %N - Fractional seconds digits, default is 9 digits (nanosecond) @@ -7018,10 +7194,14 @@ jisx0301_date_format(char *fmt, size_t size, VALUE jd, VALUE y) c = 'S'; s = 1925; } - else { + else if (d < 2458605) { c = 'H'; s = 1988; } + else { + c = 'R'; + s = 2018; + } snprintf(fmt, size, "%c%02ld" ".%%m.%%d", c, FIX2INT(y) - s); return fmt; } @@ -7099,6 +7279,10 @@ d_lite_marshal_dump(VALUE self) static VALUE d_lite_marshal_load(VALUE self, VALUE a) { + VALUE nth, sf; + int jd, df, of; + double sg; + get_d1(self); rb_check_frozen(self); @@ -7111,63 +7295,33 @@ d_lite_marshal_load(VALUE self, VALUE a) case 2: /* 1.6.x */ case 3: /* 1.8.x, 1.9.2 */ { - VALUE ajd, of, sg, nth, sf; - int jd, df, rof; - double rsg; - + VALUE ajd, vof, vsg; if (RARRAY_LEN(a) == 2) { ajd = f_sub(RARRAY_AREF(a, 0), half_days_in_day); - of = INT2FIX(0); - sg = RARRAY_AREF(a, 1); - if (!k_numeric_p(sg)) - sg = DBL2NUM(RTEST(sg) ? GREGORIAN : JULIAN); + vof = INT2FIX(0); + vsg = RARRAY_AREF(a, 1); + if (!k_numeric_p(vsg)) + vsg = DBL2NUM(RTEST(vsg) ? GREGORIAN : JULIAN); } else { ajd = RARRAY_AREF(a, 0); - of = RARRAY_AREF(a, 1); - sg = RARRAY_AREF(a, 2); + vof = RARRAY_AREF(a, 1); + vsg = RARRAY_AREF(a, 2); } - old_to_new(ajd, of, sg, - &nth, &jd, &df, &sf, &rof, &rsg); - - if (!df && f_zero_p(sf) && !rof) { - set_to_simple(self, &dat->s, nth, jd, rsg, 0, 0, 0, HAVE_JD); - } else { - if (!complex_dat_p(dat)) - rb_raise(rb_eArgError, - "cannot load complex into simple"); - - set_to_complex(self, &dat->c, nth, jd, df, sf, rof, rsg, - 0, 0, 0, 0, 0, 0, - HAVE_JD | HAVE_DF | COMPLEX_DAT); - } + old_to_new(ajd, vof, vsg, + &nth, &jd, &df, &sf, &of, &sg); } break; case 6: { - VALUE nth, sf; - int jd, df, of; - double sg; - nth = RARRAY_AREF(a, 0); jd = NUM2INT(RARRAY_AREF(a, 1)); df = NUM2INT(RARRAY_AREF(a, 2)); sf = RARRAY_AREF(a, 3); of = NUM2INT(RARRAY_AREF(a, 4)); sg = NUM2DBL(RARRAY_AREF(a, 5)); - if (!df && f_zero_p(sf) && !of) { - set_to_simple(self, &dat->s, nth, jd, sg, 0, 0, 0, HAVE_JD); - } else { - if (!complex_dat_p(dat)) - rb_raise(rb_eArgError, - "cannot load complex into simple"); - - set_to_complex(self, &dat->c, nth, jd, df, sf, of, sg, - 0, 0, 0, 0, 0, 0, - HAVE_JD | HAVE_DF | COMPLEX_DAT); - } } break; default: @@ -7175,6 +7329,18 @@ d_lite_marshal_load(VALUE self, VALUE a) break; } + if (simple_dat_p(dat)) { + if (df || !f_zero_p(sf) || of) { + rb_raise(rb_eArgError, + "cannot load complex into simple"); + } + set_to_simple(self, &dat->s, nth, jd, sg, 0, 0, 0, HAVE_JD); + } else { + set_to_complex(self, &dat->c, nth, jd, df, sf, of, sg, + 0, 0, 0, 0, 0, 0, + HAVE_JD | HAVE_DF); + } + if (FL_TEST(a, FL_EXIVAR)) { rb_copy_generic_ivar(self, a); FL_SET(self, FL_EXIVAR); @@ -7354,10 +7520,21 @@ datetime_s_ordinal(int argc, VALUE *argv, VALUE klass) */ static VALUE datetime_s_civil(int argc, VALUE *argv, VALUE klass) +{ + return datetime_initialize(argc, argv, d_lite_s_alloc_complex(klass)); +} + +static VALUE +datetime_initialize(int argc, VALUE *argv, VALUE self) { VALUE vy, vm, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret; int m, d, h, min, s, rof; double sg; + struct ComplexDateData *dat = rb_check_typeddata(self, &d_lite_type); + + if (!complex_dat_p(dat)) { + rb_raise(rb_eTypeError, "DateTime expected"); + } rb_scan_args(argc, argv, "08", &vy, &vm, &vd, &vh, &vmin, &vs, &vof, &vsg); @@ -7401,13 +7578,13 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass) rb_raise(rb_eArgError, "invalid date"); canon24oc(); - ret = d_complex_new_internal(klass, - nth, 0, - 0, INT2FIX(0), - rof, sg, - ry, rm, rd, - rh, rmin, rs, - HAVE_CIVIL | HAVE_TIME); + set_to_complex(self, dat, + nth, 0, + 0, INT2FIX(0), + rof, sg, + ry, rm, rd, + rh, rmin, rs, + HAVE_CIVIL | HAVE_TIME); } else { VALUE nth; @@ -7426,14 +7603,15 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass) time_to_df(rh, rmin, rs), rof); - ret = d_complex_new_internal(klass, - nth, rjd2, - 0, INT2FIX(0), - rof, sg, - ry, rm, rd, - rh, rmin, rs, - HAVE_JD | HAVE_CIVIL | HAVE_TIME); + set_to_complex(self, dat, + nth, rjd2, + 0, INT2FIX(0), + rof, sg, + ry, rm, rd, + rh, rmin, rs, + HAVE_JD | HAVE_CIVIL | HAVE_TIME); } + ret = self; add_frac(); return ret; } @@ -7925,7 +8103,7 @@ datetime_s_strptime(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * DateTime.parse(string='-4712-01-01T00:00:00+00:00'[, comp=true[, start=Date::ITALY]]) -> datetime + * DateTime.parse(string='-4712-01-01T00:00:00+00:00'[, comp=true[, start=Date::ITALY]], limit: 128) -> datetime * * Parses the given representation of date and time, and creates a * DateTime object. This method does not function as a validator. @@ -7939,13 +8117,18 @@ datetime_s_strptime(int argc, VALUE *argv, VALUE klass) * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> * DateTime.parse('3rd Feb 2001 04:05:06 PM') * #=> #<DateTime: 2001-02-03T16:05:06+00:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE datetime_s_parse(int argc, VALUE *argv, VALUE klass) { - VALUE str, comp, sg; + VALUE str, comp, sg, opt; - rb_scan_args(argc, argv, "03", &str, &comp, &sg); + rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -7957,18 +8140,20 @@ datetime_s_parse(int argc, VALUE *argv, VALUE klass) } { - VALUE argv2[2], hash; - - argv2[0] = str; - argv2[1] = comp; - hash = date_s__parse(2, argv2, klass); + int argc2 = 2; + VALUE argv2[3]; + argv2[0] = str; + argv2[1] = comp; + argv2[2] = opt; + if (!NIL_P(opt)) argc2++; + VALUE hash = date_s__parse(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.iso8601(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> datetime + * DateTime.iso8601(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime * * Creates a new DateTime object by parsing from a string according to * some typical ISO 8601 formats. @@ -7979,13 +8164,18 @@ datetime_s_parse(int argc, VALUE *argv, VALUE klass) * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> * DateTime.iso8601('2001-W05-6T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE datetime_s_iso8601(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -7995,27 +8185,37 @@ datetime_s_iso8601(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__iso8601(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2--; + VALUE hash = date_s__iso8601(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> datetime + * DateTime.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime * * Creates a new DateTime object by parsing from a string according to * some typical RFC 3339 formats. * * DateTime.rfc3339('2001-02-03T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -8025,27 +8225,37 @@ datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__rfc3339(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + VALUE hash = date_s__rfc3339(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.xmlschema(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> datetime + * DateTime.xmlschema(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime * * Creates a new DateTime object by parsing from a string according to * some typical XML Schema formats. * * DateTime.xmlschema('2001-02-03T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -8055,28 +8265,38 @@ datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__xmlschema(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + VALUE hash = date_s__xmlschema(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY]) -> datetime - * DateTime.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY]) -> datetime + * DateTime.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> datetime + * DateTime.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> datetime * * Creates a new DateTime object by parsing from a string according to * some typical RFC 2822 formats. * * DateTime.rfc2822('Sat, 3 Feb 2001 04:05:06 +0700') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -8086,7 +8306,12 @@ datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__rfc2822(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + VALUE hash = date_s__rfc2822(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } @@ -8100,13 +8325,18 @@ datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass) * * DateTime.httpdate('Sat, 03 Feb 2001 04:05:06 GMT') * #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE datetime_s_httpdate(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -8116,27 +8346,42 @@ datetime_s_httpdate(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__httpdate(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + VALUE hash = date_s__httpdate(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.jisx0301(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY]) -> datetime + * DateTime.jisx0301(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime * * Creates a new DateTime object by parsing from a string according to * some typical JIS X 0301 formats. * * DateTime.jisx0301('H13.02.03T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * For no-era year, legacy format, Heisei is assumed. + * + * DateTime.jisx0301('13.02.03T04:05:06+07:00') + * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing `limit: nil`, but note that + * it may take a long time to parse. */ static VALUE datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + rb_scan_args(argc, argv, "02:", &str, &sg, &opt); + if (!NIL_P(opt)) argc--; switch (argc) { case 0: @@ -8146,7 +8391,12 @@ datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass) } { - VALUE hash = date_s__jisx0301(klass, str); + int argc2 = 1; + VALUE argv2[2]; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + VALUE hash = date_s__jisx0301(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } @@ -8230,7 +8480,7 @@ dt_lite_to_s(VALUE self) * * %M - Minute of the hour (00..59) * - * %S - Second of the minute (00..59) + * %S - Second of the minute (00..60) * * %L - Millisecond of the second (000..999) * %N - Fractional seconds digits, default is 9 digits (nanosecond) @@ -8643,7 +8893,7 @@ datetime_to_date(VALUE self) VALUE new = d_lite_s_alloc_simple(cDate); { get_d1b(new); - copy_complex_to_simple(new, &bdat->s, &adat->c) + copy_complex_to_simple(new, &bdat->s, &adat->c); bdat->s.jd = m_local_jd(adat); bdat->s.flags &= ~(HAVE_DF | HAVE_TIME | COMPLEX_DAT); return new; @@ -9008,14 +9258,18 @@ mk_ary_of_str(long len, const char *a[]) return o; } +static VALUE +d_lite_zero(VALUE x) +{ + return INT2FIX(0); +} + void Init_date_core(void) { #undef rb_intern #define rb_intern(str) rb_intern_const(str) - assert(fprintf(stderr, "assert() is now active\n")); - id_cmp = rb_intern("<=>"); id_le_p = rb_intern("<="); id_ge_p = rb_intern(">="); @@ -9231,23 +9485,22 @@ Init_date_core(void) */ rb_define_const(cDate, "GREGORIAN", DBL2NUM(GREGORIAN)); - rb_define_alloc_func(cDate, d_lite_s_alloc); + rb_define_alloc_func(cDate, d_lite_s_alloc_simple); #ifndef NDEBUG -#define de_define_private_method rb_define_private_method - de_define_private_method(CLASS_OF(cDate), "_valid_jd?", + rb_define_private_method(CLASS_OF(cDate), "_valid_jd?", date_s__valid_jd_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_ordinal?", + rb_define_private_method(CLASS_OF(cDate), "_valid_ordinal?", date_s__valid_ordinal_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_civil?", + rb_define_private_method(CLASS_OF(cDate), "_valid_civil?", date_s__valid_civil_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_date?", + rb_define_private_method(CLASS_OF(cDate), "_valid_date?", date_s__valid_civil_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_commercial?", + rb_define_private_method(CLASS_OF(cDate), "_valid_commercial?", date_s__valid_commercial_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_weeknum?", + rb_define_private_method(CLASS_OF(cDate), "_valid_weeknum?", date_s__valid_weeknum_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_nth_kday?", + rb_define_private_method(CLASS_OF(cDate), "_valid_nth_kday?", date_s__valid_nth_kday_p, -1); #endif @@ -9260,11 +9513,11 @@ Init_date_core(void) date_s_valid_commercial_p, -1); #ifndef NDEBUG - de_define_private_method(CLASS_OF(cDate), "valid_weeknum?", + rb_define_private_method(CLASS_OF(cDate), "valid_weeknum?", date_s_valid_weeknum_p, -1); - de_define_private_method(CLASS_OF(cDate), "valid_nth_kday?", + rb_define_private_method(CLASS_OF(cDate), "valid_nth_kday?", date_s_valid_nth_kday_p, -1); - de_define_private_method(CLASS_OF(cDate), "zone_to_diff", + rb_define_private_method(CLASS_OF(cDate), "zone_to_diff", date_s_zone_to_diff, 1); #endif @@ -9275,21 +9528,18 @@ Init_date_core(void) date_s_gregorian_leap_p, 1); #ifndef NDEBUG -#define de_define_singleton_method rb_define_singleton_method -#define de_define_alias rb_define_alias - de_define_singleton_method(cDate, "new!", date_s_new_bang, -1); - de_define_alias(rb_singleton_class(cDate), "new_l!", "new"); + rb_define_singleton_method(cDate, "new!", date_s_new_bang, -1); + rb_define_alias(rb_singleton_class(cDate), "new_l!", "new"); #endif rb_define_singleton_method(cDate, "jd", date_s_jd, -1); rb_define_singleton_method(cDate, "ordinal", date_s_ordinal, -1); rb_define_singleton_method(cDate, "civil", date_s_civil, -1); - rb_define_singleton_method(cDate, "new", date_s_civil, -1); rb_define_singleton_method(cDate, "commercial", date_s_commercial, -1); #ifndef NDEBUG - de_define_singleton_method(cDate, "weeknum", date_s_weeknum, -1); - de_define_singleton_method(cDate, "nth_kday", date_s_nth_kday, -1); + rb_define_singleton_method(cDate, "weeknum", date_s_weeknum, -1); + rb_define_singleton_method(cDate, "nth_kday", date_s_nth_kday, -1); #endif rb_define_singleton_method(cDate, "today", date_s_today, -1); @@ -9297,29 +9547,26 @@ Init_date_core(void) rb_define_singleton_method(cDate, "strptime", date_s_strptime, -1); rb_define_singleton_method(cDate, "_parse", date_s__parse, -1); rb_define_singleton_method(cDate, "parse", date_s_parse, -1); - rb_define_singleton_method(cDate, "_iso8601", date_s__iso8601, 1); + rb_define_singleton_method(cDate, "_iso8601", date_s__iso8601, -1); rb_define_singleton_method(cDate, "iso8601", date_s_iso8601, -1); - rb_define_singleton_method(cDate, "_rfc3339", date_s__rfc3339, 1); + rb_define_singleton_method(cDate, "_rfc3339", date_s__rfc3339, -1); rb_define_singleton_method(cDate, "rfc3339", date_s_rfc3339, -1); - rb_define_singleton_method(cDate, "_xmlschema", date_s__xmlschema, 1); + rb_define_singleton_method(cDate, "_xmlschema", date_s__xmlschema, -1); rb_define_singleton_method(cDate, "xmlschema", date_s_xmlschema, -1); - rb_define_singleton_method(cDate, "_rfc2822", date_s__rfc2822, 1); - rb_define_singleton_method(cDate, "_rfc822", date_s__rfc2822, 1); + rb_define_singleton_method(cDate, "_rfc2822", date_s__rfc2822, -1); + rb_define_singleton_method(cDate, "_rfc822", date_s__rfc2822, -1); rb_define_singleton_method(cDate, "rfc2822", date_s_rfc2822, -1); rb_define_singleton_method(cDate, "rfc822", date_s_rfc2822, -1); - rb_define_singleton_method(cDate, "_httpdate", date_s__httpdate, 1); + rb_define_singleton_method(cDate, "_httpdate", date_s__httpdate, -1); rb_define_singleton_method(cDate, "httpdate", date_s_httpdate, -1); - rb_define_singleton_method(cDate, "_jisx0301", date_s__jisx0301, 1); + rb_define_singleton_method(cDate, "_jisx0301", date_s__jisx0301, -1); rb_define_singleton_method(cDate, "jisx0301", date_s_jisx0301, -1); -#ifndef NDEBUG -#define de_define_method rb_define_method - de_define_method(cDate, "initialize", d_lite_initialize, -1); -#endif + rb_define_method(cDate, "initialize", date_initialize, -1); rb_define_method(cDate, "initialize_copy", d_lite_initialize_copy, 1); #ifndef NDEBUG - de_define_method(cDate, "fill", d_lite_fill, 0); + rb_define_method(cDate, "fill", d_lite_fill, 0); #endif rb_define_method(cDate, "ajd", d_lite_ajd, 0); @@ -9341,8 +9588,8 @@ Init_date_core(void) rb_define_method(cDate, "cwday", d_lite_cwday, 0); #ifndef NDEBUG - de_define_private_method(cDate, "wnum0", d_lite_wnum0, 0); - de_define_private_method(cDate, "wnum1", d_lite_wnum1, 0); + rb_define_private_method(cDate, "wnum0", d_lite_wnum0, 0); + rb_define_private_method(cDate, "wnum1", d_lite_wnum1, 0); #endif rb_define_method(cDate, "wday", d_lite_wday, 0); @@ -9356,18 +9603,14 @@ Init_date_core(void) rb_define_method(cDate, "saturday?", d_lite_saturday_p, 0); #ifndef NDEBUG - de_define_method(cDate, "nth_kday?", d_lite_nth_kday_p, 2); + rb_define_method(cDate, "nth_kday?", d_lite_nth_kday_p, 2); #endif - rb_define_private_method(cDate, "hour", d_lite_hour, 0); - rb_define_private_method(cDate, "min", d_lite_min, 0); - rb_define_private_method(cDate, "minute", d_lite_min, 0); - rb_define_private_method(cDate, "sec", d_lite_sec, 0); - rb_define_private_method(cDate, "second", d_lite_sec, 0); - rb_define_private_method(cDate, "sec_fraction", d_lite_sec_fraction, 0); - rb_define_private_method(cDate, "second_fraction", d_lite_sec_fraction, 0); - rb_define_private_method(cDate, "offset", d_lite_offset, 0); - rb_define_private_method(cDate, "zone", d_lite_zone, 0); + rb_define_private_method(cDate, "hour", d_lite_zero, 0); + rb_define_private_method(cDate, "min", d_lite_zero, 0); + rb_define_private_method(cDate, "minute", d_lite_zero, 0); + rb_define_private_method(cDate, "sec", d_lite_zero, 0); + rb_define_private_method(cDate, "second", d_lite_zero, 0); rb_define_method(cDate, "julian?", d_lite_julian_p, 0); rb_define_method(cDate, "gregorian?", d_lite_gregorian_p, 0); @@ -9380,8 +9623,6 @@ Init_date_core(void) rb_define_method(cDate, "julian", d_lite_julian, 0); rb_define_method(cDate, "gregorian", d_lite_gregorian, 0); - rb_define_private_method(cDate, "new_offset", d_lite_new_offset, -1); - rb_define_method(cDate, "+", d_lite_plus, 1); rb_define_method(cDate, "-", d_lite_minus, 1); @@ -9409,7 +9650,7 @@ Init_date_core(void) rb_define_method(cDate, "to_s", d_lite_to_s, 0); #ifndef NDEBUG - de_define_method(cDate, "inspect_raw", d_lite_inspect_raw, 0); + rb_define_method(cDate, "inspect_raw", d_lite_inspect_raw, 0); #endif rb_define_method(cDate, "inspect", d_lite_inspect, 0); @@ -9426,7 +9667,7 @@ Init_date_core(void) rb_define_method(cDate, "jisx0301", d_lite_jisx0301, 0); #ifndef NDEBUG - de_define_method(cDate, "marshal_dump_old", d_lite_marshal_dump_old, 0); + rb_define_method(cDate, "marshal_dump_old", d_lite_marshal_dump_old, 0); #endif rb_define_method(cDate, "marshal_dump", d_lite_marshal_dump, 0); rb_define_method(cDate, "marshal_load", d_lite_marshal_load, 1); @@ -9573,6 +9814,7 @@ Init_date_core(void) */ cDateTime = rb_define_class("DateTime", cDate); + rb_define_alloc_func(cDateTime, d_lite_s_alloc_complex); rb_define_singleton_method(cDateTime, "jd", datetime_s_jd, -1); rb_define_singleton_method(cDateTime, "ordinal", datetime_s_ordinal, -1); @@ -9582,9 +9824,9 @@ Init_date_core(void) datetime_s_commercial, -1); #ifndef NDEBUG - de_define_singleton_method(cDateTime, "weeknum", + rb_define_singleton_method(cDateTime, "weeknum", datetime_s_weeknum, -1); - de_define_singleton_method(cDateTime, "nth_kday", + rb_define_singleton_method(cDateTime, "nth_kday", datetime_s_nth_kday, -1); #endif @@ -9612,19 +9854,16 @@ Init_date_core(void) rb_define_singleton_method(cDateTime, "jisx0301", datetime_s_jisx0301, -1); -#define f_public(m,s) rb_funcall(m, rb_intern("public"), 1,\ - ID2SYM(rb_intern(s))) - - f_public(cDateTime, "hour"); - f_public(cDateTime, "min"); - f_public(cDateTime, "minute"); - f_public(cDateTime, "sec"); - f_public(cDateTime, "second"); - f_public(cDateTime, "sec_fraction"); - f_public(cDateTime, "second_fraction"); - f_public(cDateTime, "offset"); - f_public(cDateTime, "zone"); - f_public(cDateTime, "new_offset"); + rb_define_method(cDateTime, "hour", d_lite_hour, 0); + rb_define_method(cDateTime, "min", d_lite_min, 0); + rb_define_method(cDateTime, "minute", d_lite_min, 0); + rb_define_method(cDateTime, "sec", d_lite_sec, 0); + rb_define_method(cDateTime, "second", d_lite_sec, 0); + rb_define_method(cDateTime, "sec_fraction", d_lite_sec_fraction, 0); + rb_define_method(cDateTime, "second_fraction", d_lite_sec_fraction, 0); + rb_define_method(cDateTime, "offset", d_lite_offset, 0); + rb_define_method(cDateTime, "zone", d_lite_zone, 0); + rb_define_method(cDateTime, "new_offset", d_lite_new_offset, -1); rb_define_method(cDateTime, "to_s", dt_lite_to_s, 0); @@ -9652,15 +9891,15 @@ Init_date_core(void) #ifndef NDEBUG /* tests */ - de_define_singleton_method(cDate, "test_civil", date_s_test_civil, 0); - de_define_singleton_method(cDate, "test_ordinal", date_s_test_ordinal, 0); - de_define_singleton_method(cDate, "test_commercial", + rb_define_singleton_method(cDate, "test_civil", date_s_test_civil, 0); + rb_define_singleton_method(cDate, "test_ordinal", date_s_test_ordinal, 0); + rb_define_singleton_method(cDate, "test_commercial", date_s_test_commercial, 0); - de_define_singleton_method(cDate, "test_weeknum", date_s_test_weeknum, 0); - de_define_singleton_method(cDate, "test_nth_kday", date_s_test_nth_kday, 0); - de_define_singleton_method(cDate, "test_unit_conv", + rb_define_singleton_method(cDate, "test_weeknum", date_s_test_weeknum, 0); + rb_define_singleton_method(cDate, "test_nth_kday", date_s_test_nth_kday, 0); + rb_define_singleton_method(cDate, "test_unit_conv", date_s_test_unit_conv, 0); - de_define_singleton_method(cDate, "test_all", date_s_test_all, 0); + rb_define_singleton_method(cDate, "test_all", date_s_test_all, 0); #endif } diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c index b74230d291..f06c07bae4 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -40,9 +40,9 @@ RUBY_EXTERN unsigned long ruby_scan_digits(const char *str, ssize_t len, int bas #define f_sub_bang(s,r,x) rb_funcall(s, rb_intern("sub!"), 2, r, x) #define f_gsub_bang(s,r,x) rb_funcall(s, rb_intern("gsub!"), 2, r, x) -#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v) -#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k))) -#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k))) +#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k"")), v) +#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k""))) +#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k""))) #define cstr2num(s) rb_cstr_to_inum(s, 10, 0) #define str2num(s) rb_str_to_inum(s, 10, 0) @@ -66,7 +66,13 @@ static const char abbr_months[][4] = { #define asubt_string() rb_str_new("\024", 1) #endif -#define DECDIGIT "0123456789" +static size_t +digit_span(const char *s, const char *e) +{ + size_t i = 0; + while (s + i < e && isdigit(s[i])) i++; + return i; +} static void s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) @@ -92,7 +98,7 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) y = d; d = Qnil; } - if (!NIL_P(d) && *RSTRING_PTR(d) == '\'') { + if (!NIL_P(d) && RSTRING_LEN(d) > 0 && *RSTRING_PTR(d) == '\'') { y = d; d = Qnil; } @@ -103,17 +109,20 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) size_t l; s = RSTRING_PTR(y); - while (!issign((unsigned char)*s) && !isdigit((unsigned char)*s)) + ep = RSTRING_END(y); + while (s < ep && !issign(*s) && !isdigit(*s)) s++; + if (s >= ep) goto no_date; bp = s; if (issign((unsigned char)*s)) s++; - l = strspn(s, DECDIGIT); + l = digit_span(s, ep); ep = s + l; if (*ep) { y = d; d = rb_str_new(bp, ep - bp); } + no_date:; } if (!NIL_P(m)) { @@ -152,8 +161,10 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) VALUE iy; s = RSTRING_PTR(y); - while (!issign((unsigned char)*s) && !isdigit((unsigned char)*s)) + ep = RSTRING_END(y); + while (s < ep && !issign(*s) && !isdigit(*s)) s++; + if (s >= ep) goto no_year; bp = s; if (issign(*s)) { s++; @@ -161,7 +172,7 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) } if (sign) c = Qfalse; - l = strspn(s, DECDIGIT); + l = digit_span(s, ep); ep = s + l; if (l > 2) c = Qfalse; @@ -175,6 +186,7 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) ALLOCV_END(vbuf); } set_hash("year", iy); + no_year:; } if (bc) @@ -186,10 +198,12 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) VALUE im; s = RSTRING_PTR(m); - while (!isdigit((unsigned char)*s)) + ep = RSTRING_END(m); + while (s < ep && !isdigit(*s)) s++; + if (s >= ep) goto no_month; bp = s; - l = strspn(s, DECDIGIT); + l = digit_span(s, ep); ep = s + l; { char *buf; @@ -201,6 +215,7 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) ALLOCV_END(vbuf); } set_hash("mon", im); + no_month:; } if (!NIL_P(d)) { @@ -209,10 +224,12 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) VALUE id; s = RSTRING_PTR(d); - while (!isdigit((unsigned char)*s)) + ep = RSTRING_END(d); + while (s < ep && !isdigit(*s)) s++; + if (s >= ep) goto no_mday; bp = s; - l = strspn(s, DECDIGIT); + l = digit_span(s, ep); ep = s + l; { char *buf; @@ -224,6 +241,7 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) ALLOCV_END(vbuf); } set_hash("mday", id); + no_mday:; } if (!NIL_P(c)) @@ -263,18 +281,18 @@ regcomp(const char *source, long len, int opt) } #define REGCOMP(pat,opt) \ -{ \ +do { \ if (NIL_P(pat)) \ pat = regcomp(pat##_source, sizeof pat##_source - 1, opt); \ -} +} while (0) #define REGCOMP_0(pat) REGCOMP(pat, 0) #define REGCOMP_I(pat) REGCOMP(pat, ONIG_OPTION_IGNORECASE) #define MATCH(s,p,c) \ -{ \ +do { \ return match(s, p, hash, c); \ -} +} while (0) static int match(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE)) @@ -314,30 +332,30 @@ subx(VALUE str, VALUE rep, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE)) } #define SUBS(s,p,c) \ -{ \ +do { \ return subx(s, asp_string(), p, hash, c); \ -} +} while (0) #ifdef TIGHT_PARSER #define SUBA(s,p,c) \ -{ \ +do { \ return subx(s, asuba_string(), p, hash, c); \ -} +} while (0) #define SUBB(s,p,c) \ -{ \ +do { \ return subx(s, asubb_string(), p, hash, c); \ -} +} while (0) #define SUBW(s,p,c) \ -{ \ +do { \ return subx(s, asubw_string(), p, hash, c); \ -} +} while (0) #define SUBT(s,p,c) \ -{ \ +do { \ return subx(s, asubt_string(), p, hash, c); \ -} +} while (0) #endif #include "zonetab.h" @@ -706,16 +724,14 @@ parse_era(VALUE str, VALUE hash) static int check_year_width(VALUE y) { - char *s; - size_t l; + const char *s; + long l; + l = RSTRING_LEN(y); + if (l < 2) return 0; s = RSTRING_PTR(y); - l = strcspn(s, DECDIGIT); - s += l; - l = strspn(s, DECDIGIT); - if (l != 2) - return 0; - return 1; + if (!isdigit(s[1])) return 0; + return (l == 2 || !isdigit(s[2])); } static int @@ -1196,6 +1212,9 @@ parse_iso2(VALUE str, VALUE hash) return 1; } +#define JISX0301_ERA_INITIALS "mtshr" +#define JISX0301_DEFAULT_ERA 'H' /* obsolete */ + static int gengo(int c) { @@ -1206,6 +1225,7 @@ gengo(int c) case 'T': case 't': e = 1911; break; case 'S': case 's': e = 1925; break; case 'H': case 'h': e = 1988; break; + case 'R': case 'r': e = 2018; break; default: e = 0; break; } return e; @@ -1236,11 +1256,11 @@ parse_jis(VALUE str, VALUE hash) { static const char pat_source[] = #ifndef TIGHT_PARSER - "\\b([mtsh])(\\d+)\\.(\\d+)\\.(\\d+)" + "\\b([" JISX0301_ERA_INITIALS "])(\\d+)\\.(\\d+)\\.(\\d+)" #else BOS FPW_COM FPT_COM - "([mtsh])(\\d+)\\.(\\d+)\\.(\\d+)" + "([" JISX0301_ERA_INITIALS "])(\\d+)\\.(\\d+)\\.(\\d+)" TEE_FPT COM_FPW EOS #endif @@ -2938,7 +2958,7 @@ jisx0301_cb(VALUE m, VALUE hash) s[i] = rb_reg_nth_match(i, m); } - ep = gengo(NIL_P(s[1]) ? 'h' : *RSTRING_PTR(s[1])); + ep = gengo(NIL_P(s[1]) ? JISX0301_DEFAULT_ERA : *RSTRING_PTR(s[1])); set_hash("year", f_add(str2num(s[2]), INT2FIX(ep))); set_hash("mon", str2num(s[3])); set_hash("mday", str2num(s[4])); @@ -2963,7 +2983,7 @@ static int jisx0301(VALUE str, VALUE hash) { static const char pat_source[] = - "\\A\\s*([mtsh])?(\\d{2})\\.(\\d{2})\\.(\\d{2})" + "\\A\\s*([" JISX0301_ERA_INITIALS "])?(\\d{2})\\.(\\d{2})\\.(\\d{2})" "(?:t" "(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d*))?)?" "(z|[-+]\\d{2}(?::?\\d{2})?)?)?)?\\s*\\z"; diff --git a/ext/date/date_strptime.c b/ext/date/date_strptime.c index 4f93219317..4383eb6fa1 100644 --- a/ext/date/date_strptime.c +++ b/ext/date/date_strptime.c @@ -79,14 +79,17 @@ read_digits(const char *s, VALUE *n, size_t width) { size_t l; - l = strspn(s, "0123456789"); + if (!width) + return 0; + + l = 0; + while (ISDIGIT(s[l])) { + if (++l == width) break; + } if (l == 0) return 0; - if (width < l) - l = width; - if ((4 * l * sizeof(char)) <= (sizeof(long)*CHAR_BIT)) { const char *os = s; long v; @@ -113,26 +116,26 @@ read_digits(const char *s, VALUE *n, size_t width) } } -#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v) -#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k))) -#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k))) +#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k"")), v) +#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k""))) +#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k""))) #define fail() \ -{ \ +do { \ set_hash("_fail", Qtrue); \ return 0; \ -} +} while (0) #define fail_p() (!NIL_P(ref_hash("_fail"))) #define READ_DIGITS(n,w) \ -{ \ +do { \ size_t l; \ l = read_digits(&str[si], &n, w); \ if (l == 0) \ fail(); \ si += l; \ -} +} while (0) #define READ_DIGITS_MAX(n) READ_DIGITS(n, LONG_MAX) @@ -147,14 +150,14 @@ valid_range_p(VALUE v, int a, int b) } #define recur(fmt) \ -{ \ +do { \ size_t l; \ l = date__strptime_internal(&str[si], slen - si, \ fmt, sizeof fmt - 1, hash); \ if (fail_p()) \ return 0; \ si += l; \ -} +} while (0) VALUE date_zone_to_diff(VALUE); @@ -237,9 +240,9 @@ date__strptime_internal(const char *str, size_t slen, VALUE n; if (NUM_PATTERN_P()) - READ_DIGITS(n, 2) + READ_DIGITS(n, 2); else - READ_DIGITS_MAX(n) + READ_DIGITS_MAX(n); set_hash("_cent", n); goto matched; } @@ -278,9 +281,9 @@ date__strptime_internal(const char *str, size_t slen, VALUE n; if (NUM_PATTERN_P()) - READ_DIGITS(n, 4) + READ_DIGITS(n, 4); else - READ_DIGITS_MAX(n) + READ_DIGITS_MAX(n); set_hash("cwyear", n); goto matched; } @@ -358,9 +361,9 @@ date__strptime_internal(const char *str, size_t slen, } osi = si; if (NUM_PATTERN_P()) - READ_DIGITS(n, c == 'L' ? 3 : 9) + READ_DIGITS(n, c == 'L' ? 3 : 9); else - READ_DIGITS_MAX(n) + READ_DIGITS_MAX(n); if (sign == -1) n = f_negate(n); set_hash("sec_fraction", @@ -426,9 +429,7 @@ date__strptime_internal(const char *str, size_t slen, if (sign == -1) n = f_negate(n); set_hash("seconds", - rb_rational_new2(n, - f_expt(INT2FIX(10), - INT2FIX(3)))); + rb_rational_new2(n, INT2FIX(1000))); goto matched; } @@ -529,24 +530,24 @@ date__strptime_internal(const char *str, size_t slen, goto matched; case 'Y': - { - VALUE n; - int sign = 1; - - if (issign(str[si])) { - if (str[si] == '-') - sign = -1; - si++; - } - if (NUM_PATTERN_P()) - READ_DIGITS(n, 4) - else - READ_DIGITS_MAX(n) + { + VALUE n; + int sign = 1; + + if (issign(str[si])) { + if (str[si] == '-') + sign = -1; + si++; + } + if (NUM_PATTERN_P()) + READ_DIGITS(n, 4); + else + READ_DIGITS_MAX(n); if (sign == -1) n = f_negate(n); - set_hash("year", n); - goto matched; - } + set_hash("year", n); + goto matched; + } case 'y': { diff --git a/ext/io/console/io-console.gemspec b/ext/io/console/io-console.gemspec index 1256162468..99e18bda9a 100644 --- a/ext/io/console/io-console.gemspec +++ b/ext/io/console/io-console.gemspec @@ -5,7 +5,7 @@ Gem::Specification.new do |s| s.name = "io-console" s.version = _VERSION - s.date = date + s.date = RUBY_RELEASE_DATE s.summary = "Console interface" s.email = "nobu@ruby-lang.org" s.description = "add console capabilities to IO instances." diff --git a/gc.c b/gc.c index c02ac627f0..fc303879eb 100644 --- a/gc.c +++ b/gc.c @@ -47,7 +47,9 @@ # endif #endif #ifdef HAVE_MALLOC_USABLE_SIZE -# ifdef HAVE_MALLOC_H +# ifdef RUBY_ALTERNATIVE_MALLOC_HEADER +# include RUBY_ALTERNATIVE_MALLOC_HEADER +# elif HAVE_MALLOC_H # include <malloc.h> # elif defined(HAVE_MALLOC_NP_H) # include <malloc_np.h> @@ -975,6 +977,31 @@ tick(void) return val; } +#elif defined(__powerpc64__) && \ + ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) +typedef unsigned long long tick_t; +#define PRItick "llu" + +static __inline__ tick_t +tick(void) +{ + unsigned long long val = __builtin_ppc_get_timebase(); + return val; +} + +#elif defined(__aarch64__) && defined(__GNUC__) +typedef unsigned long tick_t; +#define PRItick "lu" + +static __inline__ tick_t +tick(void) +{ + unsigned long val; + __asm__ __volatile__ ("mrs %0, cntvct_el0", : "=r" (val)); + return val; +} + + #elif defined(_WIN32) && defined(_MSC_VER) #include <intrin.h> typedef unsigned __int64 tick_t; diff --git a/gc.h b/gc.h index 2c91e06620..0f8a56f94d 100644 --- a/gc.h +++ b/gc.h @@ -6,6 +6,8 @@ #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movq\t%%rsp, %0" : "=r" (*(p))) #elif defined(__i386) && defined(__GNUC__) #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movl\t%%esp, %0" : "=r" (*(p))) +#elif defined(__aarch64__) && defined(__GNUC__) +#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mov\t%0, sp" : "=r" (*(p))) #else NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p)); #define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p) diff --git a/include/ruby/defines.h b/include/ruby/defines.h index 2c72a7cb8a..85f3bda3c1 100644 --- a/include/ruby/defines.h +++ b/include/ruby/defines.h @@ -358,7 +358,7 @@ void rb_ia64_flushrs(void); #ifndef UNALIGNED_WORD_ACCESS # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \ - defined(__powerpc64__) || \ + defined(__powerpc64__) || defined(__aarch64__) || \ defined(__mc68020__) # define UNALIGNED_WORD_ACCESS 1 # else diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb index a2155edb77..4410f3174f 100644 --- a/lib/cgi/cookie.rb +++ b/lib/cgi/cookie.rb @@ -40,6 +40,10 @@ class CGI class Cookie < Array @@accept_charset="UTF-8" unless defined?(@@accept_charset) + TOKEN_RE = %r"\A[[!-~]&&[^()<>@,;:\\\"/?=\[\]{}]]+\z" + PATH_VALUE_RE = %r"\A[[ -~]&&[^;]]*\z" + DOMAIN_VALUE_RE = %r"\A\.?(?<label>(?!-)[-A-Za-z0-9]+(?<!-))(?:\.\g<label>)*\z" + # Create a new CGI::Cookie object. # # :call-seq: @@ -57,7 +61,7 @@ class Cookie < Array # # name:: the name of the cookie. Required. # value:: the cookie's value or list of values. - # path:: the path for which this cookie applies. Defaults to the + # path:: the path for which this cookie applies. Defaults to # the value of the +SCRIPT_NAME+ environment variable. # domain:: the domain for which this cookie applies. # expires:: the time at which this cookie expires, as a +Time+ object. @@ -72,9 +76,8 @@ def initialize(name = "", *value) @domain = nil @expires = nil if name.kind_of?(String) - @name = name - %r|^(.*/)|.match(ENV["SCRIPT_NAME"]) - @path = ($1 or "") + self.name = name + self.path = (%r|\A(.*/)| =~ ENV["SCRIPT_NAME"] ? $1 : "") @secure = false @httponly = false return super(value) @@ -85,16 +88,11 @@ def initialize(name = "", *value) raise ArgumentError, "`name' required" end - @name = options["name"] + self.name = options["name"] value = Array(options["value"]) # simple support for IE - if options["path"] - @path = options["path"] - else - %r|^(.*/)|.match(ENV["SCRIPT_NAME"]) - @path = ($1 or "") - end - @domain = options["domain"] + self.path = options["path"] || (%r|\A(.*/)| =~ ENV["SCRIPT_NAME"] ? $1 : "") + self.domain = options["domain"] @expires = options["expires"] @secure = options["secure"] == true @httponly = options["httponly"] == true @@ -103,11 +101,35 @@ def initialize(name = "", *value) end # Name of this cookie, as a +String+ - attr_accessor :name + attr_reader :name + # Set name of this cookie + def name=(str) + if str and !TOKEN_RE.match?(str) + raise ArgumentError, "invalid name: #{str.dump}" + end + @name = str + end + # Path for which this cookie applies, as a +String+ - attr_accessor :path + attr_reader :path + # Set path for which this cookie applies + def path=(str) + if str and !PATH_VALUE_RE.match?(str) + raise ArgumentError, "invalid path: #{str.dump}" + end + @path = str + end + # Domain for which this cookie applies, as a +String+ - attr_accessor :domain + attr_reader :domain + # Set domain for which this cookie applies + def domain=(str) + if str and ((str = str.b).bytesize > 255 or !DOMAIN_VALUE_RE.match?(str)) + raise ArgumentError, "invalid domain: #{str.dump}" + end + @domain = str + end + # Time at which this cookie expires, as a +Time+ attr_accessor :expires # True if this cookie is secure; false otherwise @@ -165,7 +187,6 @@ def self.parse(raw_cookie) raw_cookie.split(/;\s?/).each do |pairs| name, values = pairs.split('=',2) next unless name and values - name = CGI.unescape(name) values ||= "" values = values.split('&').collect{|v| CGI.unescape(v,@@accept_charset) } if cookies.has_key?(name) diff --git a/lib/cgi/core.rb b/lib/cgi/core.rb index 73daae3e17..f94f490b22 100644 --- a/lib/cgi/core.rb +++ b/lib/cgi/core.rb @@ -188,17 +188,28 @@ def http_header(options='text/html') # Using #header with the HTML5 tag maker will create a <header> element. alias :header :http_header + def _no_crlf_check(str) + if str + str = str.to_s + raise "A HTTP status or header field must not include CR and LF" if str =~ /[\r\n]/ + str + else + nil + end + end + private :_no_crlf_check + def _header_for_string(content_type) #:nodoc: buf = ''.dup if nph?() - buf << "#{$CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0'} 200 OK#{EOL}" + buf << "#{_no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0'} 200 OK#{EOL}" buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}" - buf << "Server: #{$CGI_ENV['SERVER_SOFTWARE']}#{EOL}" + buf << "Server: #{_no_crlf_check($CGI_ENV['SERVER_SOFTWARE'])}#{EOL}" buf << "Connection: close#{EOL}" end - buf << "Content-Type: #{content_type}#{EOL}" + buf << "Content-Type: #{_no_crlf_check(content_type)}#{EOL}" if @output_cookies - @output_cookies.each {|cookie| buf << "Set-Cookie: #{cookie}#{EOL}" } + @output_cookies.each {|cookie| buf << "Set-Cookie: #{_no_crlf_check(cookie)}#{EOL}" } end return buf end # _header_for_string @@ -213,9 +224,9 @@ def _header_for_hash(options) #:nodoc: ## NPH options.delete('nph') if defined?(MOD_RUBY) if options.delete('nph') || nph?() - protocol = $CGI_ENV['SERVER_PROTOCOL'] || 'HTTP/1.0' + protocol = _no_crlf_check($CGI_ENV['SERVER_PROTOCOL']) || 'HTTP/1.0' status = options.delete('status') - status = HTTP_STATUS[status] || status || '200 OK' + status = HTTP_STATUS[status] || _no_crlf_check(status) || '200 OK' buf << "#{protocol} #{status}#{EOL}" buf << "Date: #{CGI.rfc1123_date(Time.now)}#{EOL}" options['server'] ||= $CGI_ENV['SERVER_SOFTWARE'] || '' @@ -223,38 +234,38 @@ def _header_for_hash(options) #:nodoc: end ## common headers status = options.delete('status') - buf << "Status: #{HTTP_STATUS[status] || status}#{EOL}" if status + buf << "Status: #{HTTP_STATUS[status] || _no_crlf_check(status)}#{EOL}" if status server = options.delete('server') - buf << "Server: #{server}#{EOL}" if server + buf << "Server: #{_no_crlf_check(server)}#{EOL}" if server connection = options.delete('connection') - buf << "Connection: #{connection}#{EOL}" if connection + buf << "Connection: #{_no_crlf_check(connection)}#{EOL}" if connection type = options.delete('type') - buf << "Content-Type: #{type}#{EOL}" #if type + buf << "Content-Type: #{_no_crlf_check(type)}#{EOL}" #if type length = options.delete('length') - buf << "Content-Length: #{length}#{EOL}" if length + buf << "Content-Length: #{_no_crlf_check(length)}#{EOL}" if length language = options.delete('language') - buf << "Content-Language: #{language}#{EOL}" if language + buf << "Content-Language: #{_no_crlf_check(language)}#{EOL}" if language expires = options.delete('expires') buf << "Expires: #{CGI.rfc1123_date(expires)}#{EOL}" if expires ## cookie if cookie = options.delete('cookie') case cookie when String, Cookie - buf << "Set-Cookie: #{cookie}#{EOL}" + buf << "Set-Cookie: #{_no_crlf_check(cookie)}#{EOL}" when Array arr = cookie - arr.each {|c| buf << "Set-Cookie: #{c}#{EOL}" } + arr.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" } when Hash hash = cookie - hash.each_value {|c| buf << "Set-Cookie: #{c}#{EOL}" } + hash.each_value {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" } end end if @output_cookies - @output_cookies.each {|c| buf << "Set-Cookie: #{c}#{EOL}" } + @output_cookies.each {|c| buf << "Set-Cookie: #{_no_crlf_check(c)}#{EOL}" } end ## other headers options.each do |key, value| - buf << "#{key}: #{value}#{EOL}" + buf << "#{_no_crlf_check(key)}: #{_no_crlf_check(value)}#{EOL}" end return buf end # _header_for_hash diff --git a/lib/cgi/version.rb b/lib/cgi/version.rb new file mode 100644 index 0000000000..ee0c748069 --- /dev/null +++ b/lib/cgi/version.rb @@ -0,0 +1,3 @@ +class CGI + VERSION = "0.1.0.2" +end diff --git a/lib/net/ftp.rb b/lib/net/ftp.rb index 9902f9dc65..338dbbc5a8 100644 --- a/lib/net/ftp.rb +++ b/lib/net/ftp.rb @@ -97,6 +97,10 @@ class FTP < Protocol # When +true+, the connection is in passive mode. Default: +true+. attr_accessor :passive + # When +true+, use the IP address in PASV responses. Otherwise, it uses + # the same IP address for the control connection. Default: +false+. + attr_accessor :use_pasv_ip + # When +true+, all traffic to and from the server is written # to +$stdout+. Default: +false+. attr_accessor :debug_mode @@ -205,6 +209,9 @@ def FTP.open(host, *args) # handshake. # See Net::FTP#ssl_handshake_timeout for # details. Default: +nil+. + # use_pasv_ip:: When +true+, use the IP address in PASV responses. + # Otherwise, it uses the same IP address for the control + # connection. Default: +false+. # debug_mode:: When +true+, all traffic to and from the server is # written to +$stdout+. Default: +false+. # @@ -265,6 +272,7 @@ def initialize(host = nil, user_or_options = {}, passwd = nil, acct = nil) @open_timeout = options[:open_timeout] @ssl_handshake_timeout = options[:ssl_handshake_timeout] @read_timeout = options[:read_timeout] || 60 + @use_pasv_ip = options[:use_pasv_ip] || false if host connect(host, options[:port] || FTP_PORT) if options[:username] @@ -1330,7 +1338,12 @@ def parse227(resp) # :nodoc: raise FTPReplyError, resp end if m = /\((?<host>\d+(,\d+){3}),(?<port>\d+,\d+)\)/.match(resp) - return parse_pasv_ipv4_host(m["host"]), parse_pasv_port(m["port"]) + if @use_pasv_ip + host = parse_pasv_ipv4_host(m["host"]) + else + host = @sock.peeraddr[3] + end + return host, parse_pasv_port(m["port"]) else raise FTPProtoError, resp end diff --git a/lib/net/imap.rb b/lib/net/imap.rb index da7d0d555c..eedcb4f5cf 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -1213,12 +1213,14 @@ def get_tagged_response(tag, cmd) end resp = @tagged_responses.delete(tag) case resp.name + when /\A(?:OK)\z/ni + return resp when /\A(?:NO)\z/ni raise NoResponseError, resp when /\A(?:BAD)\z/ni raise BadResponseError, resp else - return resp + raise UnknownResponseError, resp end end @@ -3714,6 +3716,10 @@ class BadResponseError < ResponseError class ByeResponseError < ResponseError end + # Error raised upon an unknown response from the server. + class UnknownResponseError < ResponseError + end + RESPONSE_ERRORS = Hash.new(ResponseError) RESPONSE_ERRORS["NO"] = NoResponseError RESPONSE_ERRORS["BAD"] = BadResponseError diff --git a/lib/rdoc/rdoc.gemspec b/lib/rdoc/rdoc.gemspec index 8c92908a66..0e6c0c7292 100644 --- a/lib/rdoc/rdoc.gemspec +++ b/lib/rdoc/rdoc.gemspec @@ -7,6 +7,7 @@ Gem::Specification.new do |s| s.name = "rdoc" + s.date = RUBY_RELEASE_DATE s.version = RDoc::VERSION s.date = "2017-12-24" diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb index 68775c8be1..073f621362 100644 --- a/lib/rdoc/rdoc.rb +++ b/lib/rdoc/rdoc.rb @@ -433,7 +433,7 @@ def remove_unparseable files files.reject do |file| file =~ /\.(?:class|eps|erb|scpt\.txt|svg|ttf|yml)$/i or (file =~ /tags$/i and - open(file, 'rb') { |io| + File.open(file, 'rb') { |io| io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/ }) end diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index b472b97a07..3fd5566e6a 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -109,9 +109,12 @@ class TarInvalidError < Error; end def self.build spec, skip_validation=false gem_file = spec.file_name + spec_file = spec.loaded_from + spec_file = "Gemfile" if spec_file.nil? || spec_file.empty? package = new gem_file package.spec = spec + package.build_time = File.stat(spec_file).mtime.to_i package.build skip_validation gem_file @@ -195,6 +198,7 @@ def add_contents tar # :nodoc: digests = tar.add_file_signed 'data.tar.gz', 0444, @signer do |io| gzip_to io do |gz_io| Gem::Package::TarWriter.new gz_io do |data_tar| + data_tar.mtime = @build_time add_files data_tar end end diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb index 390f7851a3..e3fa2ee86d 100644 --- a/lib/rubygems/package/tar_writer.rb +++ b/lib/rubygems/package/tar_writer.rb @@ -91,12 +91,15 @@ def self.new(io) nil end + attr_accessor :mtime + ## # Creates a new TarWriter that will write to +io+ def initialize(io) @io = io @closed = false + @mtime = Time.now end ## @@ -125,7 +128,7 @@ def add_file(name, mode) # :yields: io header = Gem::Package::TarHeader.new :name => name, :mode => mode, :size => size, :prefix => prefix, - :mtime => Time.now + :mtime => mtime @io.write header @io.pos = final_pos @@ -220,7 +223,7 @@ def add_file_simple(name, mode, size) # :yields: io header = Gem::Package::TarHeader.new(:name => name, :mode => mode, :size => size, :prefix => prefix, - :mtime => Time.now).to_s + :mtime => mtime).to_s @io.write header os = BoundedStream.new @io, size @@ -301,7 +304,7 @@ def mkdir(name, mode) header = Gem::Package::TarHeader.new :name => name, :mode => mode, :typeflag => "5", :size => 0, :prefix => prefix, - :mtime => Time.now + :mtime => mtime @io.write header diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 2560324b7a..07fdd30a62 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -1787,7 +1787,9 @@ def date= date raise(Gem::InvalidSpecificationException, "invalid date format in specification: #{date.inspect}") end - when Time, DateLike then + when Time then + Time.utc(date.utc.year, date.utc.month, date.utc.day) + when DateLike then Time.utc(date.year, date.month, date.day) else TODAY diff --git a/lib/time.rb b/lib/time.rb index eb46a03ad3..cb6f1e47b8 100644 --- a/lib/time.rb +++ b/lib/time.rb @@ -474,8 +474,8 @@ def rfc2822(date) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+ (\d{2,})\s+ (\d{2})\s* - :\s*(\d{2})\s* - (?::\s*(\d{2}))?\s+ + :\s*(\d{2}) + (?:\s*:\s*(\d\d))?\s+ ([+-]\d{4}| UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-IK-Z])/ix =~ date # Since RFC 2822 permit comments, the regexp has no right anchor. diff --git a/lib/uri/rfc2396_parser.rb b/lib/uri/rfc2396_parser.rb index b9e7b2b26e..c7c3ecd96d 100644 --- a/lib/uri/rfc2396_parser.rb +++ b/lib/uri/rfc2396_parser.rb @@ -502,8 +502,8 @@ def initialize_regexp(pattern) ret = {} # for URI::split - ret[:ABS_URI] = Regexp.new('\A\s*' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED) - ret[:REL_URI] = Regexp.new('\A\s*' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED) + ret[:ABS_URI] = Regexp.new('\A\s*+' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED) + ret[:REL_URI] = Regexp.new('\A\s*+' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED) # for URI::extract ret[:URI_REF] = Regexp.new(pattern[:URI_REF]) diff --git a/lib/uri/rfc3986_parser.rb b/lib/uri/rfc3986_parser.rb index 871280044a..db7f64ff4d 100644 --- a/lib/uri/rfc3986_parser.rb +++ b/lib/uri/rfc3986_parser.rb @@ -106,7 +106,7 @@ def default_regexp # :nodoc: QUERY: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/, FRAGMENT: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/, OPAQUE: /\A(?:[^\/].*)?\z/, - PORT: /\A[\x09\x0a\x0c\x0d ]*\d*[\x09\x0a\x0c\x0d ]*\z/, + PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\z/, } end diff --git a/regint.h b/regint.h index a2f5bbba1d..0740429688 100644 --- a/regint.h +++ b/regint.h @@ -52,7 +52,7 @@ #ifndef UNALIGNED_WORD_ACCESS # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \ - defined(__powerpc64__) || \ + defined(__powerpc64__) || defined(__aarch64__) || \ defined(__mc68020__) # define UNALIGNED_WORD_ACCESS 1 # else diff --git a/siphash.c b/siphash.c index 153d2c690a..ddf8ee245d 100644 --- a/siphash.c +++ b/siphash.c @@ -30,7 +30,7 @@ #ifndef UNALIGNED_WORD_ACCESS # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \ - defined(__powerpc64__) || \ + defined(__powerpc64__) || defined(__aarch64__) || \ defined(__mc68020__) # define UNALIGNED_WORD_ACCESS 1 # endif diff --git a/st.c b/st.c index d44c979e19..e74523001b 100644 --- a/st.c +++ b/st.c @@ -1744,7 +1744,7 @@ st_values_check(st_table *tab, st_data_t *values, st_index_t size, #ifndef UNALIGNED_WORD_ACCESS # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \ - defined(__powerpc64__) || \ + defined(__powerpc64__) || defined(__aarch64__) || \ defined(__mc68020__) # define UNALIGNED_WORD_ACCESS 1 # endif diff --git a/test/cgi/test_cgi_cookie.rb b/test/cgi/test_cgi_cookie.rb index 115a57e4a1..e3ec4bea52 100644 --- a/test/cgi/test_cgi_cookie.rb +++ b/test/cgi/test_cgi_cookie.rb @@ -60,6 +60,24 @@ def test_cgi_cookie_new_complex end + def test_cgi_cookie_new_with_domain + h = {'name'=>'name1', 'value'=>'value1'} + cookie = CGI::Cookie.new('domain'=>'a.example.com', **h) + assert_equal('a.example.com', cookie.domain) + + cookie = CGI::Cookie.new('domain'=>'1.example.com', **h) + assert_equal('1.example.com', cookie.domain, 'enhanced by RFC 1123') + + assert_raise(ArgumentError) { + CGI::Cookie.new('domain'=>'-a.example.com', **h) + } + + assert_raise(ArgumentError) { + CGI::Cookie.new('domain'=>'a-.example.com', **h) + } + end + + def test_cgi_cookie_scriptname cookie = CGI::Cookie.new('name1', 'value1') assert_equal('', cookie.path) @@ -101,6 +119,11 @@ def test_cgi_cookie_parse end end + def test_cgi_cookie_parse_not_decode_name + cookie_str = "%66oo=baz;foo=bar" + cookies = CGI::Cookie.parse(cookie_str) + assert_equal({"%66oo" => ["baz"], "foo" => ["bar"]}, cookies) + end def test_cgi_cookie_arrayinterface cookie = CGI::Cookie.new('name1', 'a', 'b', 'c') @@ -113,6 +136,70 @@ def test_cgi_cookie_arrayinterface end + def test_cgi_cookie_domain_injection_into_name + name = "a=b; domain=example.com;" + path = "/" + domain = "example.jp" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + + + def test_cgi_cookie_newline_injection_into_name + name = "a=b;\r\nLocation: http://example.com#" + path = "/" + domain = "example.jp" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + + + def test_cgi_cookie_multibyte_injection_into_name + name = "a=b;\u3042" + path = "/" + domain = "example.jp" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + + + def test_cgi_cookie_injection_into_path + name = "name" + path = "/; samesite=none" + domain = "example.jp" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + + + def test_cgi_cookie_injection_into_domain + name = "name" + path = "/" + domain = "example.jp; samesite=none" + assert_raise(ArgumentError) do + CGI::Cookie.new('name' => name, + 'value' => "value", + 'domain' => domain, + 'path' => path) + end + end + instance_methods.each do |method| private method if method =~ /^test_(.*)/ && $1 != ENV['TEST'] diff --git a/test/cgi/test_cgi_header.rb b/test/cgi/test_cgi_header.rb index bab2d0348a..ec2f4deb72 100644 --- a/test/cgi/test_cgi_header.rb +++ b/test/cgi/test_cgi_header.rb @@ -176,6 +176,14 @@ def test_cgi_http_header_nph end + def test_cgi_http_header_crlf_injection + cgi = CGI.new + assert_raise(RuntimeError) { cgi.http_header("text/xhtml\r\nBOO") } + assert_raise(RuntimeError) { cgi.http_header("type" => "text/xhtml\r\nBOO") } + assert_raise(RuntimeError) { cgi.http_header("status" => "200 OK\r\nBOO") } + assert_raise(RuntimeError) { cgi.http_header("location" => "text/xhtml\r\nBOO") } + end + instance_methods.each do |method| private method if method =~ /^test_(.*)/ && $1 != ENV['TEST'] diff --git a/test/date/test_date_arith.rb b/test/date/test_date_arith.rb index d0d27d72f7..e1f29dbf22 100644 --- a/test/date/test_date_arith.rb +++ b/test/date/test_date_arith.rb @@ -3,11 +3,18 @@ require 'date' class TestDateArith < Test::Unit::TestCase + class Rat < Numeric + def to_r; self; end + end - def new_offset + def test_new_offset d = DateTime.new(2002, 3, 14) assert_equal(Rational(9, 24), d.new_offset(Rational(9, 24)).offset) assert_equal(Rational(9, 24), d.new_offset('+0900').offset) + n = Rat.new + assert_raise(TypeError) do + Timeout.timeout(1) {d.new_offset(n)} + end end def test__plus @@ -37,6 +44,13 @@ def test__plus__ex assert_raise(e) do DateTime.new(2000,2,29) + Time.mktime(2000,2,29) end + n = Rat.new + assert_raise(e) do + Timeout.timeout(1) {Date.new(2000,2,29) + n} + end + assert_raise(e) do + Timeout.timeout(1) {DateTime.new(2000,2,29) + n} + end end def test__minus diff --git a/test/date/test_date_attr.rb b/test/date/test_date_attr.rb index b3b5d3a800..1e4d1bfd7a 100644 --- a/test/date/test_date_attr.rb +++ b/test/date/test_date_attr.rb @@ -88,16 +88,16 @@ def test__wday_predicate end def test_nth_kday - assert_equal(false, Date.new(2001,1,14).__send__(:nth_kday?, 1,0)) - assert_equal(true, Date.new(2001,1,14).__send__(:nth_kday?, 2,0)) - assert_equal(false, Date.new(2001,1,14).__send__(:nth_kday?, 3,0)) - assert_equal(false, Date.new(2001,1,14).__send__(:nth_kday?, 4,0)) - assert_equal(false, Date.new(2001,1,14).__send__(:nth_kday?, 5,0)) - assert_equal(false, Date.new(2001,1,14).__send__(:nth_kday?, -1,0)) - assert_equal(false, Date.new(2001,1,14).__send__(:nth_kday?, -2,0)) - assert_equal(true, Date.new(2001,1,14).__send__(:nth_kday?, -3,0)) - assert_equal(false, Date.new(2001,1,14).__send__(:nth_kday?, -4,0)) - assert_equal(false, Date.new(2001,1,14).__send__(:nth_kday?, -5,0)) + assert_equal(false, Date.new(2001,1,14).nth_kday?(1,0)) + assert_equal(true, Date.new(2001,1,14).nth_kday?(2,0)) + assert_equal(false, Date.new(2001,1,14).nth_kday?(3,0)) + assert_equal(false, Date.new(2001,1,14).nth_kday?(4,0)) + assert_equal(false, Date.new(2001,1,14).nth_kday?(5,0)) + assert_equal(false, Date.new(2001,1,14).nth_kday?(-1,0)) + assert_equal(false, Date.new(2001,1,14).nth_kday?(-2,0)) + assert_equal(true, Date.new(2001,1,14).nth_kday?(-3,0)) + assert_equal(false, Date.new(2001,1,14).nth_kday?(-4,0)) + assert_equal(false, Date.new(2001,1,14).nth_kday?(-5,0)) end if Date.new.respond_to?(:nth_kday?, true) end diff --git a/test/date/test_date_marshal.rb b/test/date/test_date_marshal.rb index 99a7239f95..c7ce737aac 100644 --- a/test/date/test_date_marshal.rb +++ b/test/date/test_date_marshal.rb @@ -30,13 +30,23 @@ def test_marshal a = d.marshal_dump d.freeze assert(d.frozen?) - assert_raise(FrozenError){d.marshal_load(a)} + expected_error = defined?(FrozenError) ? FrozenError : RuntimeError + assert_raise(expected_error){d.marshal_load(a)} d = DateTime.now a = d.marshal_dump d.freeze assert(d.frozen?) - assert_raise(FrozenError){d.marshal_load(a)} + expected_error = defined?(FrozenError) ? FrozenError : RuntimeError + assert_raise(expected_error){d.marshal_load(a)} end + def test_memsize + require 'objspace' + t = DateTime.new(2018, 11, 13) + size = ObjectSpace.memsize_of(t) + t2 = Marshal.load(Marshal.dump(t)) + assert_equal(t, t2) + assert_equal(size, ObjectSpace.memsize_of(t2), "not reallocated but memsize changed") + end end diff --git a/test/date/test_date_new.rb b/test/date/test_date_new.rb index fe9a631ad0..d27116b198 100644 --- a/test/date/test_date_new.rb +++ b/test/date/test_date_new.rb @@ -203,46 +203,46 @@ def test_commercial__ex end def test_weeknum - d = Date.__send__(:weeknum) - dt = DateTime.__send__(:weeknum) + d = Date.weeknum + dt = DateTime.weeknum assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) assert_equal([-4712, 1, 1], [dt.year, dt.mon, dt.mday]) assert_equal([0, 0, 0], [dt.hour, dt.min, dt.sec]) - d = Date.__send__(:weeknum, 2002,11,4, 0) + d = Date.weeknum(2002,11,4, 0) assert_equal(2452355, d.jd) - d = DateTime.__send__(:weeknum, 2002,11,4, 0, 11,22,33) + d = DateTime.weeknum(2002,11,4, 0, 11,22,33) assert_equal(2452355, d.jd) assert_equal([11,22,33], [d.hour, d.min, d.sec]) assert_raise(ArgumentError) do - Date.__send__(:weeknum, 1999,53,0, 0) + Date.weeknum(1999,53,0, 0) end assert_raise(ArgumentError) do - Date.__send__(:weeknum, 1999,-53,-1, 0) + Date.weeknum(1999,-53,-1, 0) end end if Date.respond_to?(:weeknum, true) def test_nth_kday - d = Date.__send__(:nth_kday) - dt = DateTime.__send__(:nth_kday) + d = Date.nth_kday + dt = DateTime.nth_kday assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) assert_equal([-4712, 1, 1], [dt.year, dt.mon, dt.mday]) assert_equal([0, 0, 0], [dt.hour, dt.min, dt.sec]) - d = Date.__send__(:nth_kday, 1992,2, 5,6) + d = Date.nth_kday(1992,2, 5,6) assert_equal(2448682, d.jd) - d = DateTime.__send__(:nth_kday, 1992,2, 5,6, 11,22,33) + d = DateTime.nth_kday(1992,2, 5,6, 11,22,33) assert_equal(2448682, d.jd) assert_equal([11,22,33], [d.hour, d.min, d.sec]) assert_raise(ArgumentError) do - Date.__send__(:nth_kday, 2006,5, 5,0) + Date.nth_kday(2006,5, 5,0) end assert_raise(ArgumentError) do - Date.__send__(:nth_kday, 2006,5, -5,0) + Date.nth_kday(2006,5, -5,0) end end if Date.respond_to?(:nth_kday, true) @@ -267,4 +267,12 @@ def test_now assert_in_delta(t, t2, t - z + 2) end + def test_memsize + require 'objspace' + t = DateTime.now + size = ObjectSpace.memsize_of(t) + t.__send__(:initialize_copy, Date.today) + assert_instance_of(DateTime, t) + assert_equal(size, ObjectSpace.memsize_of(t), "not reallocated but memsize changed") + end end diff --git a/test/date/test_date_parse.rb b/test/date/test_date_parse.rb index ac0eb85ca7..d1163b29cb 100644 --- a/test/date/test_date_parse.rb +++ b/test/date/test_date_parse.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'test/unit' require 'date' +require 'timeout' class TestDateParse < Test::Unit::TestCase @@ -823,6 +824,13 @@ def test__iso8601 h = Date._iso8601('') assert_equal({}, h) + + h = Date._iso8601(nil) + assert_equal({}, h) + + h = Date._iso8601('01-02-03T04:05:06Z'.to_sym) + assert_equal([2001, 2, 3, 4, 5, 6, 0], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end def test__rfc3339 @@ -838,6 +846,13 @@ def test__rfc3339 h = Date._rfc3339('') assert_equal({}, h) + + h = Date._rfc3339(nil) + assert_equal({}, h) + + h = Date._rfc3339('2001-02-03T04:05:06Z'.to_sym) + assert_equal([2001, 2, 3, 4, 5, 6, 0], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end def test__xmlschema @@ -920,6 +935,13 @@ def test__xmlschema h = Date._xmlschema('') assert_equal({}, h) + + h = Date._xmlschema(nil) + assert_equal({}, h) + + h = Date._xmlschema('2001-02-03'.to_sym) + assert_equal([2001, 2, 3, nil, nil, nil, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end def test__rfc2822 @@ -952,6 +974,13 @@ def test__rfc2822 h = Date._rfc2822('') assert_equal({}, h) + + h = Date._rfc2822(nil) + assert_equal({}, h) + + h = Date._rfc2822('Sat, 3 Feb 2001 04:05:06 UT'.to_sym) + assert_equal([2001, 2, 3, 4, 5, 6, 0], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end def test__httpdate @@ -972,6 +1001,13 @@ def test__httpdate h = Date._httpdate('') assert_equal({}, h) + + h = Date._httpdate(nil) + assert_equal({}, h) + + h = Date._httpdate('Sat, 03 Feb 2001 04:05:06 GMT'.to_sym) + assert_equal([2001, 2, 3, 4, 5, 6, 0], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end def test__jisx0301 @@ -984,6 +1020,15 @@ def test__jisx0301 h = Date._jisx0301('S63.02.03') assert_equal([1988, 2, 3, nil, nil, nil, nil], h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('H31.04.30') + assert_equal([2019, 4, 30, nil, nil, nil, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('H31.05.01') + assert_equal([2019, 5, 1, nil, nil, nil, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('R01.05.01') + assert_equal([2019, 5, 1, nil, nil, nil, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) h = Date._jisx0301('H13.02.03T04:05:06') assert_equal([2001, 2, 3, 4, 5, 6, nil], @@ -998,8 +1043,54 @@ def test__jisx0301 assert_equal([2001, 2, 3, 4, 5, 6, 3600], h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('H31.04.30T04:05:06') + assert_equal([2019, 4, 30, 4, 5, 6, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('H31.04.30T04:05:06,07') + assert_equal([2019, 4, 30, 4, 5, 6, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('H31.04.30T04:05:06Z') + assert_equal([2019, 4, 30, 4, 5, 6, 0], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('H31.04.30T04:05:06.07+0100') + assert_equal([2019, 4, 30, 4, 5, 6, 3600], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + + h = Date._jisx0301('H31.05.01T04:05:06') + assert_equal([2019, 5, 1, 4, 5, 6, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('H31.05.01T04:05:06,07') + assert_equal([2019, 5, 1, 4, 5, 6, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('H31.05.01T04:05:06Z') + assert_equal([2019, 5, 1, 4, 5, 6, 0], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('H31.05.01T04:05:06.07+0100') + assert_equal([2019, 5, 1, 4, 5, 6, 3600], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + + h = Date._jisx0301('R01.05.01T04:05:06') + assert_equal([2019, 5, 1, 4, 5, 6, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('R01.05.01T04:05:06,07') + assert_equal([2019, 5, 1, 4, 5, 6, nil], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('R01.05.01T04:05:06Z') + assert_equal([2019, 5, 1, 4, 5, 6, 0], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('R01.05.01T04:05:06.07+0100') + assert_equal([2019, 5, 1, 4, 5, 6, 3600], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) + h = Date._jisx0301('') assert_equal({}, h) + + h = Date._jisx0301(nil) + assert_equal({}, h) + + h = Date._jisx0301('H13.02.03T04:05:06.07+0100'.to_sym) + assert_equal([2001, 2, 3, 4, 5, 6, 3600], + h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end def test_iso8601 @@ -1083,9 +1174,33 @@ def test_jisx0301 assert_equal(Date.new(2001,2,3), d) assert_equal(Date::ITALY + 10, d.start) + d = Date.jisx0301('H31.04.30', Date::ITALY + 10) + assert_equal(Date.new(2019,4,30), d) + assert_equal(Date::ITALY + 10, d.start) + + d = Date.jisx0301('H31.05.01', Date::ITALY + 10) + assert_equal(Date.new(2019,5,1), d) + assert_equal(Date::ITALY + 10, d.start) + + d = Date.jisx0301('R01.05.01', Date::ITALY + 10) + assert_equal(Date.new(2019,5,1), d) + assert_equal(Date::ITALY + 10, d.start) + d = DateTime.jisx0301('H13.02.03T04:05:06+07:00', Date::ITALY + 10) assert_equal(DateTime.new(2001,2,3,4,5,6,'+07:00'), d) assert_equal(Date::ITALY + 10, d.start) + + d = DateTime.jisx0301('H31.04.30T04:05:06+07:00', Date::ITALY + 10) + assert_equal(DateTime.new(2019,4,30,4,5,6,'+07:00'), d) + assert_equal(Date::ITALY + 10, d.start) + + d = DateTime.jisx0301('H31.05.01T04:05:06+07:00', Date::ITALY + 10) + assert_equal(DateTime.new(2019,5,1,4,5,6,'+07:00'), d) + assert_equal(Date::ITALY + 10, d.start) + + d = DateTime.jisx0301('R01.05.01T04:05:06+07:00', Date::ITALY + 10) + assert_equal(DateTime.new(2019,5,1,4,5,6,'+07:00'), d) + assert_equal(Date::ITALY + 10, d.start) end def test_given_string @@ -1122,4 +1237,32 @@ def test_given_string assert_equal(s0, s) end + def test_length_limit + assert_raise(ArgumentError) { Date._parse("1" * 1000) } + assert_raise(ArgumentError) { Date._iso8601("1" * 1000) } + assert_raise(ArgumentError) { Date._rfc3339("1" * 1000) } + assert_raise(ArgumentError) { Date._xmlschema("1" * 1000) } + assert_raise(ArgumentError) { Date._rfc2822("1" * 1000) } + assert_raise(ArgumentError) { Date._rfc822("1" * 1000) } + assert_raise(ArgumentError) { Date._jisx0301("1" * 1000) } + + assert_raise(ArgumentError) { Date.parse("1" * 1000) } + assert_raise(ArgumentError) { Date.iso8601("1" * 1000) } + assert_raise(ArgumentError) { Date.rfc3339("1" * 1000) } + assert_raise(ArgumentError) { Date.xmlschema("1" * 1000) } + assert_raise(ArgumentError) { Date.rfc2822("1" * 1000) } + assert_raise(ArgumentError) { Date.rfc822("1" * 1000) } + assert_raise(ArgumentError) { Date.jisx0301("1" * 1000) } + + assert_raise(ArgumentError) { DateTime.parse("1" * 1000) } + assert_raise(ArgumentError) { DateTime.iso8601("1" * 1000) } + assert_raise(ArgumentError) { DateTime.rfc3339("1" * 1000) } + assert_raise(ArgumentError) { DateTime.xmlschema("1" * 1000) } + assert_raise(ArgumentError) { DateTime.rfc2822("1" * 1000) } + assert_raise(ArgumentError) { DateTime.rfc822("1" * 1000) } + assert_raise(ArgumentError) { DateTime.jisx0301("1" * 1000) } + + assert_raise(ArgumentError) { Date._parse("Jan " + "9" * 1000000) } + assert_raise(Timeout::Error) { Timeout.timeout(1) { Date._parse("Jan " + "9" * 1000000, limit: nil) } } + end end diff --git a/test/date/test_date_strftime.rb b/test/date/test_date_strftime.rb index a33eaa340f..dc237a909d 100644 --- a/test/date/test_date_strftime.rb +++ b/test/date/test_date_strftime.rb @@ -406,6 +406,8 @@ def test__different_format assert_equal('S64.01.07', Date.parse('1989-01-07').jisx0301) assert_equal('H01.01.08', Date.parse('1989-01-08').jisx0301) assert_equal('H18.09.01', Date.parse('2006-09-01').jisx0301) + assert_equal('H31.04.30', Date.parse('2019-04-30').jisx0301) + assert_equal('R01.05.01', Date.parse('2019-05-01').jisx0301) %w(M06.01.01 M45.07.29 @@ -414,7 +416,10 @@ def test__different_format S01.12.25 S64.01.07 H01.01.08 - H18.09.01).each do |s| + H18.09.01 + H31.04.30 + R01.05.01 + ).each do |s| assert_equal(s, Date.parse(s).jisx0301) end diff --git a/test/date/test_switch_hitter.rb b/test/date/test_switch_hitter.rb index 16814d44df..4693cbd466 100644 --- a/test/date/test_switch_hitter.rb +++ b/test/date/test_switch_hitter.rb @@ -187,18 +187,18 @@ def test_fractional d = Date.jd(Rational(2451944)) assert_equal(2451944, d.jd) d = Date.jd(2451944.5) - assert_equal([2451944, 12], [d.jd, d.send('hour')]) + assert_equal(2451944, d.jd) d = Date.jd(Rational('2451944.5')) - assert_equal([2451944, 12], [d.jd, d.send('hour')]) + assert_equal(2451944, d.jd) d = Date.civil(2001, 2, 3.0) assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) d = Date.civil(2001, 2, Rational(3)) assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) d = Date.civil(2001, 2, 3.5) - assert_equal([2001, 2, 3, 12], [d.year, d.mon, d.mday, d.send('hour')]) + assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) d = Date.civil(2001, 2, Rational('3.5')) - assert_equal([2001, 2, 3, 12], [d.year, d.mon, d.mday, d.send('hour')]) + assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) d = Date.ordinal(2001, 2.0) assert_equal([2001, 2], [d.year, d.yday]) @@ -266,10 +266,8 @@ def test_canon24oc end def test_zone - d = Date.new(2001, 2, 3) - assert_equal(Encoding::US_ASCII, d.send(:zone).encoding) d = DateTime.new(2001, 2, 3) - assert_equal(Encoding::US_ASCII, d.send(:zone).encoding) + assert_equal(Encoding::US_ASCII, d.zone.encoding) end def test_to_s @@ -534,7 +532,6 @@ def test_marshal14 s = "\x04\x03u:\x01\x04Date\x01\v\x04\x03[\x01\x02i\x03\xE8i%T" d = Marshal.load(s) assert_equal(Rational(4903887,2), d.ajd) - assert_equal(0, d.send(:offset)) assert_equal(Date::GREGORIAN, d.start) end @@ -542,7 +539,6 @@ def test_marshal16 s = "\x04\x06u:\tDate\x0F\x04\x06[\ai\x03\xE8i%T" d = Marshal.load(s) assert_equal(Rational(4903887,2), d.ajd) - assert_equal(0, d.send(:offset)) assert_equal(Date::GREGORIAN, d.start) end @@ -550,7 +546,6 @@ def test_marshal18 s = "\x04\bu:\tDateP\x04\b[\bo:\rRational\a:\x0F@numeratori\x03\xCF\xD3J:\x11@denominatori\ai\x00o:\x13Date::Infinity\x06:\a@di\xFA" d = Marshal.load(s) assert_equal(Rational(4903887,2), d.ajd) - assert_equal(0, d.send(:offset)) assert_equal(Date::GREGORIAN, d.start) s = "\x04\bu:\rDateTime`\x04\b[\bo:\rRational\a:\x0F@numeratorl+\b\xC9\xB0\x81\xBD\x02\x00:\x11@denominatori\x02\xC0\x12o;\x00\a;\x06i\b;\ai\ro:\x13Date::Infinity\x06:\a@di\xFA" @@ -564,7 +559,6 @@ def test_marshal192 s = "\x04\bU:\tDate[\bU:\rRational[\ai\x03\xCF\xD3Ji\ai\x00o:\x13Date::Infinity\x06:\a@di\xFA" d = Marshal.load(s) assert_equal(Rational(4903887,2), d.ajd) - assert_equal(Rational(0,24), d.send(:offset)) assert_equal(Date::GREGORIAN, d.start) s = "\x04\bU:\rDateTime[\bU:\rRational[\al+\b\xC9\xB0\x81\xBD\x02\x00i\x02\xC0\x12U;\x06[\ai\bi\ro:\x13Date::Infinity\x06:\a@di\xFA" diff --git a/test/net/ftp/test_ftp.rb b/test/net/ftp/test_ftp.rb index 8e0a688135..7a85488ddb 100644 --- a/test/net/ftp/test_ftp.rb +++ b/test/net/ftp/test_ftp.rb @@ -62,6 +62,7 @@ def test_connect_fail def test_parse227 ftp = Net::FTP.new + ftp.use_pasv_ip = true host, port = ftp.send(:parse227, "227 Entering Passive Mode (192,168,0,1,12,34)") assert_equal("192.168.0.1", host) assert_equal(3106, port) @@ -80,6 +81,12 @@ def test_parse227 assert_raise(Net::FTPProtoError) do ftp.send(:parse227, "227 ) foo bar (") end + ftp = Net::FTP.new + sock = OpenStruct.new + sock.peeraddr = [nil, nil, nil, "10.0.0.1"] + ftp.instance_variable_set(:@sock, sock) + host, port = ftp.send(:parse227, "227 Entering Passive Mode (192,168,0,1,12,34)") + assert_equal("10.0.0.1", host) end def test_parse228 diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb index 41f25fe1c7..e43a793cda 100644 --- a/test/net/imap/test_imap.rb +++ b/test/net/imap/test_imap.rb @@ -127,6 +127,16 @@ def test_starttls imap.disconnect end end + + def test_starttls_stripping + starttls_stripping_test do |port| + imap = Net::IMAP.new("localhost", :port => port) + assert_raise(Net::IMAP::UnknownResponseError) do + imap.starttls(:ca_file => CA_FILE) + end + imap + end + end end def test_unexpected_eof @@ -760,6 +770,27 @@ def starttls_test end end + def starttls_stripping_test + server = create_tcp_server + port = server.addr[1] + @threads << Thread.start do + sock = server.accept + begin + sock.print("* OK test server\r\n") + sock.gets + sock.print("RUBY0001 BUG unhandled command\r\n") + ensure + sock.close + server.close + end + end + begin + imap = yield(port) + ensure + imap.disconnect if imap && !imap.disconnected? + end + end + def create_tcp_server return TCPServer.new(server_addr, 0) end diff --git a/test/rdoc/test_rdoc_rdoc.rb b/test/rdoc/test_rdoc_rdoc.rb index bd4794342c..4cbcbd0d53 100644 --- a/test/rdoc/test_rdoc_rdoc.rb +++ b/test/rdoc/test_rdoc_rdoc.rb @@ -366,6 +366,19 @@ def test_remove_unparseable_tags_vim end end + def test_remove_unparseable_CVE_2021_31799 + omit 'for Un*x platforms' if Gem.win_platform? + temp_dir do + file_list = ['| touch evil.txt && echo tags'] + file_list.each do |f| + FileUtils.touch f + end + + assert_equal file_list, @rdoc.remove_unparseable(file_list) + assert_equal file_list, Dir.children('.') + end + end + def test_setup_output_dir Dir.mktmpdir {|d| path = File.join d, 'testdir' diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb index 7fabfd351d..78c63c26bf 100644 --- a/test/ruby/test_float.rb +++ b/test/ruby/test_float.rb @@ -171,6 +171,24 @@ def test_strtod assert_raise(ArgumentError, n += z + "A") {Float(n)} assert_raise(ArgumentError, n += z + ".0") {Float(n)} end + + x = nil + 2000.times do + x = Float("0x"+"0"*30) + break unless x == 0.0 + end + assert_equal(0.0, x, ->{"%a" % x}) + x = nil + 2000.times do + begin + x = Float("0x1."+"0"*270) + rescue ArgumentError => e + raise unless /"0x1\.0{270}"/ =~ e.message + else + break + end + end + assert_nil(x, ->{"%a" % x}) end def test_divmod diff --git a/test/uri/test_parser.rb b/test/uri/test_parser.rb index 757ac86c74..157761efa3 100644 --- a/test/uri/test_parser.rb +++ b/test/uri/test_parser.rb @@ -45,4 +45,49 @@ def test_raise_bad_uri_for_integer URI.parse(1) end end + + def test_unescape + p1 = URI::Parser.new + assert_equal("\xe3\x83\x90", p1.unescape("\xe3\x83\x90")) + assert_equal("\xe3\x83\x90", p1.unescape('%e3%83%90')) + assert_equal("\u3042", p1.unescape('%e3%81%82'.force_encoding(Encoding::US_ASCII))) + assert_equal("\xe3\x83\x90\xe3\x83\x90", p1.unescape("\xe3\x83\x90%e3%83%90")) + end + + def test_split + assert_equal(["http", nil, "example.com", nil, nil, "", nil, nil, nil], URI.split("http://example.com")) + assert_equal(["http", nil, "[0::0]", nil, nil, "", nil, nil, nil], URI.split("http://[0::0]")) + assert_equal([nil, nil, "example.com", nil, nil, "", nil, nil, nil], URI.split("//example.com")) + assert_equal([nil, nil, "[0::0]", nil, nil, "", nil, nil, nil], URI.split("//[0::0]")) + + assert_equal(["a", nil, nil, nil, nil, "", nil, nil, nil], URI.split("a:")) + assert_raise(URI::InvalidURIError) do + URI.parse("::") + end + assert_raise(URI::InvalidURIError) do + URI.parse("foo@example:foo") + end + end + + def test_rfc2822_parse_relative_uri + pre = ->(length) { + " " * length + "\0" + } + parser = URI::RFC2396_Parser.new + assert_linear_performance((1..5).map {|i| 10**i}, pre: pre) do |uri| + assert_raise(URI::InvalidURIError) do + parser.split(uri) + end + end + end + + def test_rfc3986_port_check + pre = ->(length) {"\t" * length + "a"} + uri = URI.parse("http://my.example.com") + assert_linear_performance((1..5).map {|i| 10**i}, pre: pre) do |port| + assert_raise(URI::InvalidComponentError) do + uri.port = port + end + end + end end diff --git a/util.c b/util.c index 757faee396..4e60f72c03 100644 --- a/util.c +++ b/util.c @@ -2046,6 +2046,7 @@ break2: if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; if (*s == '0') { while (*++s == '0'); + if (!*s) goto ret; s1 = strchr(hexdigit, *s); } if (s1 != NULL) { @@ -2068,7 +2069,7 @@ break2: for (; *s && (s1 = strchr(hexdigit, *s)); ++s) { adj += aadj * ((s1 - hexdigit) & 15); if ((aadj /= 16) == 0.0) { - while (strchr(hexdigit, *++s)); + while (*++s && strchr(hexdigit, *s)); break; } } diff --git a/vm_exec.c b/vm_exec.c index ce47ab2cc3..60788e55a7 100644 --- a/vm_exec.c +++ b/vm_exec.c @@ -27,6 +27,9 @@ static void vm_analysis_insn(int insn); #elif defined(__GNUC__) && defined(__powerpc64__) #define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg) +#elif defined(__GNUC__) && defined(__aarch64__) +#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("x" reg) + #else #define DECL_SC_REG(type, r, reg) register type reg_##r #endif @@ -74,6 +77,11 @@ vm_exec_core(rb_execution_context_t *ec, VALUE initial) DECL_SC_REG(rb_control_frame_t *, cfp, "15"); #define USE_MACHINE_REGS 1 +#elif defined(__GNUC__) && defined(__aarch64__) + DECL_SC_REG(const VALUE *, pc, "19"); + DECL_SC_REG(rb_control_frame_t *, cfp, "20"); +#define USE_MACHINE_REGS 1 + #else register rb_control_frame_t *reg_cfp; const VALUE *reg_pc;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor