diff options
-rw-r--r-- | ext/date/date_parse.c | 112 | ||||
-rw-r--r-- | ext/date/prereq.mk | 2 | ||||
-rw-r--r-- | ext/date/zonetab.h | 57 | ||||
-rw-r--r-- | test/date/test_date_strptime.rb | 3 |
4 files changed, 122 insertions, 52 deletions
diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c index ab46bda4ad..8717850eba 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -361,64 +361,88 @@ do { \ #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 = 0; + sp = 1; } } - if (d > dest) { - if (*(d - 1) == ' ') - --d; - *d = '\0'; + 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; + } } - 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) { + char *d = ALLOCV_N(char, vbuf, sl); + l = shrink_space(d, s, l); + s = d; + } } { const struct zone *z = zonetab(s, (unsigned int)l); @@ -436,8 +460,8 @@ date_zone_to_diff(VALUE str) 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; } diff --git a/ext/date/prereq.mk b/ext/date/prereq.mk index c0c55d2c27..4aff03a4f6 100644 --- a/ext/date/prereq.mk +++ b/ext/date/prereq.mk @@ -1,7 +1,7 @@ .SUFFIXES: .list .list.h: - gperf -E -C -c -P -p -j1 -i 1 -g -o -t -N $(*F) $< \ + gperf --ignore-case -E -C -c -P -p -j1 -i 1 -g -o -t -N $(*F) $< \ | sed -f $(top_srcdir)/tool/gperf.sed \ > $(@F) diff --git a/ext/date/zonetab.h b/ext/date/zonetab.h index 2dfa9b988a..c76056d548 100644 --- a/ext/date/zonetab.h +++ b/ext/date/zonetab.h @@ -1,5 +1,5 @@ /* ANSI-C code produced by gperf version 3.1 */ -/* Command-line: gperf -E -C -c -P -p -j1 -i 1 -g -o -t -N zonetab zonetab.list */ +/* Command-line: gperf --ignore-case -E -C -c -P -p -j1 -i 1 -g -o -t -N zonetab zonetab.list */ /* Computed positions: -k'1-4,$' */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ @@ -41,6 +41,51 @@ static const struct zone *zonetab(); struct zone; /* maximum key range = 434, duplicates = 0 */ +#ifndef GPERF_DOWNCASE +#define GPERF_DOWNCASE 1 +static unsigned char gperf_downcase[256] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255 + }; +#endif + +#ifndef GPERF_CASE_STRNCMP +#define GPERF_CASE_STRNCMP 1 +static int +gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n) +{ + for (; n > 0;) + { + unsigned char c1 = gperf_downcase[(unsigned char)*s1++]; + unsigned char c2 = gperf_downcase[(unsigned char)*s2++]; + if (c1 != 0 && c1 == c2) + { + n--; + continue; + } + return (int)c1 - (int)c2; + } + return 0; +} +#endif + #ifdef __GNUC__ __inline #else @@ -59,10 +104,10 @@ hash (register const char *str, register size_t len) 439, 439, 19, 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, 2, 4, 439, 439, 439, 439, 439, 8, 6, 3, 439, 439, 439, 439, 439, - 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, - 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, - 439, 439, 439, 439, 439, 439, 439, 439, 439, 439, - 439, 439, 439, 439, 439, 439, 439, 7, 63, 53, + 439, 439, 439, 439, 439, 7, 63, 53, 2, 4, + 32, 110, 88, 78, 90, 68, 47, 108, 10, 73, + 81, 124, 3, 1, 4, 77, 116, 88, 15, 96, + 45, 5, 439, 439, 439, 439, 439, 7, 63, 53, 2, 4, 32, 110, 88, 78, 90, 68, 47, 108, 10, 73, 81, 124, 3, 1, 4, 77, 116, 88, 15, 96, 45, 5, 439, 439, 439, 439, 439, 439, @@ -884,7 +929,7 @@ zonetab (register const char *str, register size_t len) { register const char *s = o + stringpool; - if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0') return &wordlist[key]; } } diff --git a/test/date/test_date_strptime.rb b/test/date/test_date_strptime.rb index bf3002a24a..bbc0da5ac0 100644 --- a/test/date/test_date_strptime.rb +++ b/test/date/test_date_strptime.rb @@ -178,7 +178,8 @@ class TestDateStrptime < Test::Unit::TestCase [['11:33:44 PM AMT', '%I:%M:%S %p %Z'], [nil,nil,nil,23,33,44,'AMT',nil,nil], __LINE__], [['11:33:44 P.M. AMT', '%I:%M:%S %p %Z'], [nil,nil,nil,23,33,44,'AMT',nil,nil], __LINE__], - [['fri1feb034pm+5', '%a%d%b%y%H%p%Z'], [2003,2,1,16,nil,nil,'+5',5*3600,5]] + [['fri1feb034pm+5', '%a%d%b%y%H%p%Z'], [2003,2,1,16,nil,nil,'+5',5*3600,5]], + [['E. Australia Standard Time', '%Z'], [nil,nil,nil,nil,nil,nil,'E. Australia Standard Time',10*3600,nil], __LINE__], ].each do |x, y| h = Date._strptime(*x) a = h.values_at(:year,:mon,:mday,:hour,:min,:sec,:zone,:offset,:wday) |