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+))?)?"