ext/date/date_parse.c in date-2.0.3 vs ext/date/date_parse.c in date-3.0.0

- old
+ new

@@ -359,70 +359,94 @@ #endif #include "zonetab.h" static int -str_end_with(const char *s, long l, const char *w) +str_end_with_word(const char *s, long l, const char *w) { int n = (int)strlen(w); - return (l >= n && strncmp(s - n, w, n) == 0); + if (l <= n || !isspace(s[l - n - 1])) return 0; + if (strncasecmp(&s[l - n], w, n)) return 0; + do ++n; while (l > n && isspace(s[l - n - 1])); + return n; } -VALUE -date_zone_to_diff(VALUE str) +static long +shrunk_size(const char *s, long l) { - VALUE offset = Qnil; - VALUE vbuf = 0; - - long l, i; - char *s, *dest, *d; - int sp = 1; - - l = RSTRING_LEN(str); - s = RSTRING_PTR(str); - - dest = d = ALLOCV_N(char, vbuf, l + 1); - - for (i = 0; i < l; i++) { - if (isspace((unsigned char)s[i]) || s[i] == '\0') { - if (!sp) - *d++ = ' '; - sp = 1; + long i, ni; + int sp = 0; + for (i = ni = 0; i < l; ++i) { + if (!isspace(s[i])) { + if (sp) ni++; + sp = 0; + ni++; } else { - if (isalpha((unsigned char)s[i])) - *d++ = tolower((unsigned char)s[i]); - else - *d++ = s[i]; + sp = 1; + } + } + return ni < l ? ni : 0; +} + +static long +shrink_space(char *d, const char *s, long l) +{ + long i, ni; + int sp = 0; + for (i = ni = 0; i < l; ++i) { + if (!isspace(s[i])) { + if (sp) d[ni++] = ' '; sp = 0; + d[ni++] = s[i]; } + else { + sp = 1; + } } - if (d > dest) { - if (*(d - 1) == ' ') - --d; - *d = '\0'; - } - l = d - dest; - s = dest; + return ni; +} + +VALUE +date_zone_to_diff(VALUE str) +{ + VALUE offset = Qnil; + VALUE vbuf = 0; + long l = RSTRING_LEN(str); + const char *s = RSTRING_PTR(str); + { - static const char STD[] = " standard time"; - static const char DST1[] = " daylight time"; - static const char DST2[] = " dst"; int dst = 0; + int w; - if (str_end_with(d, l, STD)) { - l -= sizeof(STD) - 1; + if ((w = str_end_with_word(s, l, "time")) > 0) { + int wtime = w; + l -= w; + if ((w = str_end_with_word(s, l, "standard")) > 0) { + l -= w; + } + else if ((w = str_end_with_word(s, l, "daylight")) > 0) { + l -= w; + dst = 1; + } + else { + l += wtime; + } } - else if (str_end_with(d, l, DST1)) { - l -= sizeof(DST1) - 1; + else if ((w = str_end_with_word(s, l, "dst")) > 0) { + l -= w; dst = 1; } - else if (str_end_with(d, l, DST2)) { - l -= sizeof(DST2) - 1; - dst = 1; - } { + long sl = shrunk_size(s, l); + if (sl > 0 && sl <= MAX_WORD_LENGTH) { + char *d = ALLOCV_N(char, vbuf, sl); + l = shrink_space(d, s, l); + s = d; + } + } + if (l > 0 && l <= MAX_WORD_LENGTH) { const struct zone *z = zonetab(s, (unsigned int)l); if (z) { int d = z->offset; if (dst) d += 3600; @@ -434,12 +458,12 @@ char *p; int sign = 0; long hour = 0, min = 0, sec = 0; if (l > 3 && - (strncmp(s, "gmt", 3) == 0 || - strncmp(s, "utc", 3) == 0)) { + (strncasecmp(s, "gmt", 3) == 0 || + strncasecmp(s, "utc", 3) == 0)) { s += 3; l -= 3; } if (issign(*s)) { sign = *s == '-'; @@ -1861,34 +1885,30 @@ l5 = RSTRING_LEN(s5); set_hash("zone", s5); if (*cs5 == '[') { - VALUE vbuf = 0; - char *buf = ALLOCV_N(char, vbuf, l5 + 1); - char *s1, *s2, *s3; + const char *s1, *s2; VALUE zone; - memcpy(buf, cs5, l5); - buf[l5 - 1] = '\0'; - - s1 = buf + 1; - s2 = strchr(buf, ':'); + l5 -= 2; + s1 = cs5 + 1; + s2 = memchr(s1, ':', l5); if (s2) { - *s2 = '\0'; s2++; + zone = rb_str_subseq(s5, s2 - cs5, l5 - (s2 - s1)); + s5 = rb_str_subseq(s5, 1, s2 - s1); } - if (s2) - s3 = s2; - else - s3 = s1; - zone = rb_str_new2(s3); + else { + zone = rb_str_subseq(s5, 1, l5); + if (isdigit((unsigned char)*s1)) + s5 = rb_str_append(rb_str_new_cstr("+"), zone); + else + s5 = zone; + } set_hash("zone", zone); - if (isdigit((unsigned char)*s1)) - *--s1 = '+'; - set_hash("offset", date_zone_to_diff(rb_str_new2(s1))); - ALLOCV_END(vbuf); + set_hash("offset", date_zone_to_diff(s5)); } RB_GC_GUARD(s5); } return 1; @@ -2177,11 +2197,11 @@ if (HAVE_ELEM_P(HAVE_DIGIT)) parse_frag(str, hash); #endif { - if (RTEST(ref_hash("_bc"))) { + if (RTEST(del_hash("_bc"))) { VALUE y; y = ref_hash("cwyear"); if (!NIL_P(y)) { y = f_add(f_negate(y), INT2FIX(1)); @@ -2192,11 +2212,11 @@ y = f_add(f_negate(y), INT2FIX(1)); set_hash("year", y); } } - if (RTEST(ref_hash("_comp"))) { + if (RTEST(del_hash("_comp"))) { VALUE y; y = ref_hash("cwyear"); if (!NIL_P(y)) if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) { @@ -2215,13 +2235,10 @@ } } } - del_hash("_bc"); - del_hash("_comp"); - { VALUE zone = ref_hash("zone"); if (!NIL_P(zone) && NIL_P(ref_hash("offset"))) set_hash("offset", date_zone_to_diff(zone)); } @@ -2267,12 +2284,12 @@ s[0] = Qnil; for (i = 1; i <= SNUM; i++) s[i] = rb_reg_nth_match(i, m); } - if (!NIL_P(s[3])) { - set_hash("mday", str2num(s[3])); + if (!NIL_P(s[1])) { + if (!NIL_P(s[3])) set_hash("mday", str2num(s[3])); if (strcmp(RSTRING_PTR(s[1]), "-") != 0) { y = str2num(s[1]); if (RSTRING_LEN(s[1]) < 4) y = comp_year69(y); set_hash("year", y); @@ -2325,10 +2342,10 @@ static int iso8601_ext_datetime(VALUE str, VALUE hash) { static const char pat_source[] = - "\\A\\s*(?:([-+]?\\d{2,}|-)-(\\d{2})?-(\\d{2})|" + "\\A\\s*(?:([-+]?\\d{2,}|-)-(\\d{2})?(?:-(\\d{2}))?|" "([-+]?\\d{2,})?-(\\d{3})|" "(\\d{4}|\\d{2})?-w(\\d{2})-(\\d)|" "-w-(\\d))" "(?:t" "(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?)?"