Ruby 1.9.3p327(2012-11-10revision37606)
ext/date/date_parse.c
Go to the documentation of this file.
00001 /*
00002   date_parse.c: Coded by Tadayoshi Funaba 2011,2012
00003 */
00004 
00005 #include "ruby.h"
00006 #include "ruby/encoding.h"
00007 #include "ruby/re.h"
00008 #include <ctype.h>
00009 
00010 #define sizeof_array(o) (sizeof o / sizeof o[0])
00011 
00012 #define f_negate(x) rb_funcall(x, rb_intern("-@"), 0)
00013 #define f_add(x,y) rb_funcall(x, '+', 1, y)
00014 #define f_sub(x,y) rb_funcall(x, '-', 1, y)
00015 #define f_mul(x,y) rb_funcall(x, '*', 1, y)
00016 #define f_div(x,y) rb_funcall(x, '/', 1, y)
00017 #define f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y)
00018 #define f_mod(x,y) rb_funcall(x, '%', 1, y)
00019 #define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y)
00020 
00021 #define f_lt_p(x,y) rb_funcall(x, '<', 1, y)
00022 #define f_gt_p(x,y) rb_funcall(x, '>', 1, y)
00023 #define f_le_p(x,y) rb_funcall(x, rb_intern("<="), 1, y)
00024 #define f_ge_p(x,y) rb_funcall(x, rb_intern(">="), 1, y)
00025 
00026 #define f_to_s(x) rb_funcall(x, rb_intern("to_s"), 0)
00027 
00028 #define f_match(r,s) rb_funcall(r, rb_intern("match"), 1, s)
00029 #define f_aref(o,i) rb_funcall(o, rb_intern("[]"), 1, i)
00030 #define f_aref2(o,i,j) rb_funcall(o, rb_intern("[]"), 2, i, j)
00031 #define f_begin(o,i) rb_funcall(o, rb_intern("begin"), 1, i)
00032 #define f_end(o,i) rb_funcall(o, rb_intern("end"), 1, i)
00033 #define f_aset(o,i,v) rb_funcall(o, rb_intern("[]="), 2, i, v)
00034 #define f_aset2(o,i,j,v) rb_funcall(o, rb_intern("[]="), 3, i, j, v)
00035 #define f_sub_bang(s,r,x) rb_funcall(s, rb_intern("sub!"), 2, r, x)
00036 #define f_gsub_bang(s,r,x) rb_funcall(s, rb_intern("gsub!"), 2, r, x)
00037 
00038 #define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v)
00039 #define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k)))
00040 #define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k)))
00041 
00042 #define cstr2num(s) rb_cstr_to_inum(s, 10, 0)
00043 #define str2num(s) rb_str_to_inum(s, 10, 0)
00044 
00045 static const char *abbr_days[] = {
00046     "sun", "mon", "tue", "wed",
00047     "thu", "fri", "sat"
00048 };
00049 
00050 static const char *abbr_months[] = {
00051     "jan", "feb", "mar", "apr", "may", "jun",
00052     "jul", "aug", "sep", "oct", "nov", "dec"
00053 };
00054 
00055 #define issign(c) ((c) == '-' || (c) == '+')
00056 #define asp_string() rb_str_new(" ", 1)
00057 
00058 static void
00059 s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc)
00060 {
00061     VALUE c = Qnil;
00062 
00063     if (TYPE(m) != T_STRING)
00064         m = f_to_s(m);
00065 
00066     if (!NIL_P(y) && !NIL_P(m) && NIL_P(d)) {
00067         VALUE oy = y;
00068         VALUE om = m;
00069         VALUE od = d;
00070 
00071         y = od;
00072         m = oy;
00073         d = om;
00074     }
00075 
00076     if (NIL_P(y)) {
00077         if (!NIL_P(d) && RSTRING_LEN(d) > 2) {
00078             y = d;
00079             d = Qnil;
00080         }
00081         if (!NIL_P(d) && *RSTRING_PTR(d) == '\'') {
00082             y = d;
00083             d = Qnil;
00084         }
00085     }
00086 
00087     if (!NIL_P(y)) {
00088         const char *s, *bp, *ep;
00089         size_t l;
00090 
00091         s = RSTRING_PTR(y);
00092         while (!issign(*s) && !isdigit(*s))
00093             s++;
00094         bp = s;
00095         if (issign(*s))
00096             s++;
00097         l = strspn(s, "0123456789");
00098         ep = s + l;
00099         if (*ep) {
00100             y = d;
00101             d = rb_str_new(bp, ep - bp);
00102         }
00103     }
00104 
00105     if (!NIL_P(m)) {
00106         const char *s;
00107 
00108         s = RSTRING_PTR(m);
00109         if (*s == '\'' || RSTRING_LEN(m) > 2) {
00110             /* us -> be */
00111             VALUE oy = y;
00112             VALUE om = m;
00113             VALUE od = d;
00114 
00115             y = om;
00116             m = od;
00117             d = oy;
00118         }
00119     }
00120 
00121     if (!NIL_P(d)) {
00122         const char *s;
00123 
00124         s = RSTRING_PTR(d);
00125         if (*s == '\'' || RSTRING_LEN(d) > 2) {
00126             VALUE oy = y;
00127             VALUE od = d;
00128 
00129             y = od;
00130             d = oy;
00131         }
00132     }
00133 
00134     if (!NIL_P(y)) {
00135         const char *s, *bp, *ep;
00136         int sign = 0;
00137         size_t l;
00138         VALUE iy;
00139 
00140         s = RSTRING_PTR(y);
00141         while (!issign(*s) && !isdigit(*s))
00142             s++;
00143         bp = s;
00144         if (issign(*s)) {
00145             s++;
00146             sign = 1;
00147         }
00148         if (sign)
00149             c = Qfalse;
00150         l = strspn(s, "0123456789");
00151         ep = s + l;
00152         if (l > 2)
00153             c = Qfalse;
00154         {
00155             char *buf;
00156 
00157             buf = ALLOCA_N(char, ep - bp + 1);
00158             memcpy(buf, bp, ep - bp);
00159             buf[ep - bp] = '\0';
00160             iy = cstr2num(buf);
00161         }
00162         if (bc)
00163             iy = f_add(f_negate(iy), INT2FIX(1));
00164         set_hash("year", iy);
00165     }
00166 
00167     if (!NIL_P(m)) {
00168         const char *s, *bp, *ep;
00169         size_t l;
00170         VALUE im;
00171 
00172         s = RSTRING_PTR(m);
00173         while (!isdigit(*s))
00174             s++;
00175         bp = s;
00176         l = strspn(s, "0123456789");
00177         ep = s + l;
00178         {
00179             char *buf;
00180 
00181             buf = ALLOCA_N(char, ep - bp + 1);
00182             memcpy(buf, bp, ep - bp);
00183             buf[ep - bp] = '\0';
00184             im = cstr2num(buf);
00185         }
00186         set_hash("mon", im);
00187     }
00188 
00189     if (!NIL_P(d)) {
00190         const char *s, *bp, *ep;
00191         size_t l;
00192         VALUE id;
00193 
00194         s = RSTRING_PTR(d);
00195         while (!isdigit(*s))
00196             s++;
00197         bp = s;
00198         l = strspn(s, "0123456789");
00199         ep = s + l;
00200         {
00201             char *buf;
00202 
00203             buf = ALLOCA_N(char, ep - bp + 1);
00204             memcpy(buf, bp, ep - bp);
00205             buf[ep - bp] = '\0';
00206             id = cstr2num(buf);
00207         }
00208         set_hash("mday", id);
00209     }
00210 
00211     if (!NIL_P(c))
00212         set_hash("_comp", c);
00213 }
00214 
00215 #define DAYS "sunday|monday|tuesday|wednesday|thursday|friday|saturday"
00216 #define MONTHS "january|february|march|april|may|june|july|august|september|october|november|december"
00217 #define ABBR_DAYS "sun|mon|tue|wed|thu|fri|sat"
00218 #define ABBR_MONTHS "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec"
00219 
00220 static VALUE
00221 regcomp(const char *source, long len, int opt)
00222 {
00223     VALUE pat;
00224 
00225     pat = rb_reg_new(source, len, opt);
00226     rb_gc_register_mark_object(pat);
00227     return pat;
00228 }
00229 
00230 #define REGCOMP(pat,opt) \
00231 { \
00232     if (NIL_P(pat)) \
00233         pat = regcomp(pat##_source, sizeof pat##_source - 1, opt); \
00234 }
00235 
00236 #define REGCOMP_0(pat) REGCOMP(pat, 0)
00237 #define REGCOMP_I(pat) REGCOMP(pat, ONIG_OPTION_IGNORECASE)
00238 
00239 #define MATCH(s,p,c) \
00240 { \
00241     return match(s, p, hash, c); \
00242 }
00243 
00244 static int
00245 match(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE))
00246 {
00247     VALUE m;
00248 
00249     m = f_match(pat, str);
00250 
00251     if (NIL_P(m))
00252         return 0;
00253 
00254     (*cb)(m, hash);
00255 
00256     return 1;
00257 }
00258 
00259 #define SUBS(s,p,c) \
00260 { \
00261     return subs(s, p, hash, c); \
00262 }
00263 
00264 static int
00265 subs(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE))
00266 {
00267     VALUE m;
00268 
00269     m = f_match(pat, str);
00270 
00271     if (NIL_P(m))
00272         return 0;
00273 
00274     {
00275         VALUE be, en;
00276 
00277         be = f_begin(m, INT2FIX(0));
00278         en = f_end(m, INT2FIX(0));
00279         f_aset2(str, be, LONG2NUM(NUM2LONG(en) - NUM2LONG(be)), asp_string());
00280         (*cb)(m, hash);
00281     }
00282 
00283     return 1;
00284 }
00285 
00286 struct zone {
00287     const char *name;
00288     int offset;
00289 };
00290 
00291 static struct zone zones_source[] = {
00292     {"ut",   0*3600}, {"gmt",  0*3600}, {"est", -5*3600}, {"edt", -4*3600},
00293     {"cst", -6*3600}, {"cdt", -5*3600}, {"mst", -7*3600}, {"mdt", -6*3600},
00294     {"pst", -8*3600}, {"pdt", -7*3600},
00295     {"a",    1*3600}, {"b",    2*3600}, {"c",    3*3600}, {"d",    4*3600},
00296     {"e",    5*3600}, {"f",    6*3600}, {"g",    7*3600}, {"h",    8*3600},
00297     {"i",    9*3600}, {"k",   10*3600}, {"l",   11*3600}, {"m",   12*3600},
00298     {"n",   -1*3600}, {"o",   -2*3600}, {"p",   -3*3600}, {"q",   -4*3600},
00299     {"r",   -5*3600}, {"s",   -6*3600}, {"t",   -7*3600}, {"u",   -8*3600},
00300     {"v",   -9*3600}, {"w",  -10*3600}, {"x",  -11*3600}, {"y",  -12*3600},
00301     {"z",    0*3600},
00302 
00303     {"utc",  0*3600}, {"wet",  0*3600},
00304     {"at",  -2*3600}, {"brst",-2*3600}, {"ndt", -(2*3600+1800)},
00305     {"art", -3*3600}, {"adt", -3*3600}, {"brt", -3*3600}, {"clst",-3*3600},
00306     {"nst", -(3*3600+1800)},
00307     {"ast", -4*3600}, {"clt", -4*3600},
00308     {"akdt",-8*3600}, {"ydt", -8*3600},
00309     {"akst",-9*3600}, {"hadt",-9*3600}, {"hdt", -9*3600}, {"yst", -9*3600},
00310     {"ahst",-10*3600},{"cat",-10*3600}, {"hast",-10*3600},{"hst",-10*3600},
00311     {"nt",  -11*3600},
00312     {"idlw",-12*3600},
00313     {"bst",  1*3600}, {"cet",  1*3600}, {"fwt",  1*3600}, {"met",  1*3600},
00314     {"mewt", 1*3600}, {"mez",  1*3600}, {"swt",  1*3600}, {"wat",  1*3600},
00315     {"west", 1*3600},
00316     {"cest", 2*3600}, {"eet",  2*3600}, {"fst",  2*3600}, {"mest", 2*3600},
00317     {"mesz", 2*3600}, {"sast", 2*3600}, {"sst",  2*3600},
00318     {"bt",   3*3600}, {"eat",  3*3600}, {"eest", 3*3600}, {"msk",  3*3600},
00319     {"msd",  4*3600}, {"zp4",  4*3600},
00320     {"zp5",  5*3600}, {"ist",  (5*3600+1800)},
00321     {"zp6",  6*3600},
00322     {"wast", 7*3600},
00323     {"cct",  8*3600}, {"sgt",  8*3600}, {"wadt", 8*3600},
00324     {"jst",  9*3600}, {"kst",  9*3600},
00325     {"east",10*3600}, {"gst", 10*3600},
00326     {"eadt",11*3600},
00327     {"idle",12*3600}, {"nzst",12*3600}, {"nzt", 12*3600},
00328     {"nzdt",13*3600},
00329 
00330     {"afghanistan",             16200}, {"alaskan",                -32400},
00331     {"arab",                    10800}, {"arabian",                 14400},
00332     {"arabic",                  10800}, {"atlantic",               -14400},
00333     {"aus central",             34200}, {"aus eastern",             36000},
00334     {"azores",                  -3600}, {"canada central",         -21600},
00335     {"cape verde",              -3600}, {"caucasus",                14400},
00336     {"cen. australia",          34200}, {"central america",        -21600},
00337     {"central asia",            21600}, {"central europe",           3600},
00338     {"central european",         3600}, {"central pacific",         39600},
00339     {"central",                -21600}, {"china",                   28800},
00340     {"dateline",               -43200}, {"e. africa",               10800},
00341     {"e. australia",            36000}, {"e. europe",                7200},
00342     {"e. south america",       -10800}, {"eastern",                -18000},
00343     {"egypt",                    7200}, {"ekaterinburg",            18000},
00344     {"fiji",                    43200}, {"fle",                      7200},
00345     {"greenland",              -10800}, {"greenwich",                   0},
00346     {"gtb",                      7200}, {"hawaiian",               -36000},
00347     {"india",                   19800}, {"iran",                    12600},
00348     {"jerusalem",                7200}, {"korea",                   32400},
00349     {"mexico",                 -21600}, {"mid-atlantic",            -7200},
00350     {"mountain",               -25200}, {"myanmar",                 23400},
00351     {"n. central asia",         21600}, {"nepal",                   20700},
00352     {"new zealand",             43200}, {"newfoundland",           -12600},
00353     {"north asia east",         28800}, {"north asia",              25200},
00354     {"pacific sa",             -14400}, {"pacific",                -28800},
00355     {"romance",                  3600}, {"russian",                 10800},
00356     {"sa eastern",             -10800}, {"sa pacific",             -18000},
00357     {"sa western",             -14400}, {"samoa",                  -39600},
00358     {"se asia",                 25200}, {"malay peninsula",         28800},
00359     {"south africa",             7200}, {"sri lanka",               21600},
00360     {"taipei",                  28800}, {"tasmania",                36000},
00361     {"tokyo",                   32400}, {"tonga",                   46800},
00362     {"us eastern",             -18000}, {"us mountain",            -25200},
00363     {"vladivostok",             36000}, {"w. australia",            28800},
00364     {"w. central africa",        3600}, {"w. europe",                3600},
00365     {"west asia",               18000}, {"west pacific",            36000},
00366     {"yakutsk",                 32400}
00367 };
00368 
00369 VALUE
00370 date_zone_to_diff(VALUE str)
00371 {
00372     VALUE offset = Qnil;
00373 
00374     long l, i;
00375     char *s, *dest, *d;
00376     int sp = 1;
00377 
00378     l = RSTRING_LEN(str);
00379     s = RSTRING_PTR(str);
00380 
00381     dest = d = ALLOCA_N(char, l + 1);
00382 
00383     for (i = 0; i < l; i++) {
00384         if (isspace(s[i]) || s[i] == '\0') {
00385             if (!sp)
00386                 *d++ = ' ';
00387             sp = 1;
00388         }
00389         else {
00390             if (isalpha(s[i]))
00391                 *d++ = tolower(s[i]);
00392             else
00393                 *d++ = s[i];
00394             sp = 0;
00395         }
00396     }
00397     if (d > dest) {
00398         if (*(d - 1) == ' ')
00399             --d;
00400         *d = '\0';
00401     }
00402     str = rb_str_new2(dest);
00403     {
00404 #define STD " standard time"
00405 #define DST " daylight time"
00406         char *ss, *ds;
00407         long sl, dl;
00408         int dst = 0;
00409 
00410         sl = RSTRING_LEN(str) - (sizeof STD - 1);
00411         ss = RSTRING_PTR(str) + sl;
00412         dl = RSTRING_LEN(str) - (sizeof DST - 1);
00413         ds = RSTRING_PTR(str) + dl;
00414 
00415         if (sl >= 0 && strcmp(ss, STD) == 0) {
00416             str = rb_str_new(RSTRING_PTR(str), sl);
00417         }
00418         else if (dl >= 0 && strcmp(ds, DST) == 0) {
00419             str = rb_str_new(RSTRING_PTR(str), dl);
00420             dst = 1;
00421         }
00422 #undef STD
00423 #undef DST
00424         else {
00425 #define DST " dst"
00426             char *ds;
00427             long dl;
00428 
00429             dl = RSTRING_LEN(str) - (sizeof DST - 1);
00430             ds = RSTRING_PTR(str) + dl;
00431 
00432             if (dl >= 0 && strcmp(ds, DST) == 0) {
00433                 str = rb_str_new(RSTRING_PTR(str), dl);
00434                 dst = 1;
00435             }
00436 #undef DST
00437         }
00438         {
00439             static VALUE zones = Qnil;
00440 
00441             if (NIL_P(zones)) {
00442                 int i;
00443 
00444                 zones = rb_hash_new();
00445                 rb_gc_register_mark_object(zones);
00446                 for (i = 0; i < (int)sizeof_array(zones_source); i++) {
00447                     VALUE name = rb_str_new2(zones_source[i].name);
00448                     VALUE offset = INT2FIX(zones_source[i].offset);
00449                     rb_hash_aset(zones, name, offset);
00450                 }
00451             }
00452 
00453             offset = f_aref(zones, str);
00454             if (!NIL_P(offset)) {
00455                 if (dst)
00456                     offset = f_add(offset, INT2FIX(3600));
00457                 goto ok;
00458             }
00459         }
00460         {
00461             char *s, *p;
00462             VALUE sign;
00463             VALUE hour = Qnil, min = Qnil, sec = Qnil;
00464             VALUE str_orig;
00465 
00466             s = RSTRING_PTR(str);
00467             str_orig = str;
00468 
00469             if (strncmp(s, "gmt", 3) == 0 ||
00470                 strncmp(s, "utc", 3) == 0)
00471                 s += 3;
00472             if (issign(*s)) {
00473                 sign = rb_str_new(s, 1);
00474                 s++;
00475 
00476                 str = rb_str_new2(s);
00477 
00478                 if (p = strchr(s, ':')) {
00479                     hour = rb_str_new(s, p - s);
00480                     s = ++p;
00481                     if (p = strchr(s, ':')) {
00482                         min = rb_str_new(s, p - s);
00483                         s = ++p;
00484                         if (p = strchr(s, ':')) {
00485                             sec = rb_str_new(s, p - s);
00486                         }
00487                         else
00488                             sec = rb_str_new2(s);
00489                     }
00490                     else
00491                         min = rb_str_new2(s);
00492                     RB_GC_GUARD(str_orig);
00493                     goto num;
00494                 }
00495                 if (strpbrk(RSTRING_PTR(str), ",.")) {
00496                     char *a, *b;
00497 
00498                     a = ALLOCA_N(char, RSTRING_LEN(str) + 1);
00499                     strcpy(a, RSTRING_PTR(str));
00500                     b = strpbrk(a, ",.");
00501                     *b = '\0';
00502                     b++;
00503 
00504                     hour = cstr2num(a);
00505                     min = f_mul(rb_rational_new2
00506                                 (cstr2num(b),
00507                                  f_expt(INT2FIX(10),
00508                                         LONG2NUM((long)strlen(b)))),
00509                                 INT2FIX(60));
00510                     goto num;
00511                 }
00512                 {
00513                     const char *cs = RSTRING_PTR(str);
00514                     long cl = RSTRING_LEN(str);
00515 
00516                     if (cl % 2) {
00517                         if (cl >= 1)
00518                             hour = rb_str_new(&cs[0], 1);
00519                         if (cl >= 3)
00520                             min  = rb_str_new(&cs[1], 2);
00521                         if (cl >= 5)
00522                             min  = rb_str_new(&cs[3], 2);
00523                     }
00524                     else {
00525                         if (cl >= 2)
00526                             hour = rb_str_new(&cs[0], 2);
00527                         if (cl >= 4)
00528                             min  = rb_str_new(&cs[2], 2);
00529                         if (cl >= 6)
00530                             sec  = rb_str_new(&cs[4], 2);
00531                     }
00532                     goto num;
00533                 }
00534               num:
00535                 if (NIL_P(hour))
00536                     offset = INT2FIX(0);
00537                 else {
00538                     if (TYPE(hour) == T_STRING)
00539                         hour = str2num(hour);
00540                     offset = f_mul(hour, INT2FIX(3600));
00541                 }
00542                 if (!NIL_P(min)) {
00543                     if (TYPE(min) == T_STRING)
00544                         min = str2num(min);
00545                     offset = f_add(offset, f_mul(min, INT2FIX(60)));
00546                 }
00547                 if (!NIL_P(sec))
00548                     offset = f_add(offset, str2num(sec));
00549                 if (!NIL_P(sign) &&
00550                     RSTRING_LEN(sign) == 1 &&
00551                     *RSTRING_PTR(sign) == '-')
00552                     offset = f_negate(offset);
00553             }
00554         }
00555     }
00556     RB_GC_GUARD(str);
00557   ok:
00558     return offset;
00559 }
00560 
00561 static int
00562 day_num(VALUE s)
00563 {
00564     int i;
00565 
00566     for (i = 0; i < (int)sizeof_array(abbr_days); i++)
00567         if (strncasecmp(abbr_days[i], RSTRING_PTR(s), 3) == 0)
00568             break;
00569     return i;
00570 }
00571 
00572 static int
00573 mon_num(VALUE s)
00574 {
00575     int i;
00576 
00577     for (i = 0; i < (int)sizeof_array(abbr_months); i++)
00578         if (strncasecmp(abbr_months[i], RSTRING_PTR(s), 3) == 0)
00579             break;
00580     return i + 1;
00581 }
00582 
00583 static int
00584 parse_day_cb(VALUE m, VALUE hash)
00585 {
00586     VALUE s;
00587 
00588     s = rb_reg_nth_match(1, m);
00589     set_hash("wday", INT2FIX(day_num(s)));
00590     return 1;
00591 }
00592 
00593 static int
00594 parse_day(VALUE str, VALUE hash)
00595 {
00596     static const char pat_source[] = "\\b(" ABBR_DAYS ")[^-\\d\\s]*";
00597     static VALUE pat = Qnil;
00598 
00599     REGCOMP_I(pat);
00600     SUBS(str, pat, parse_day_cb);
00601 }
00602 
00603 static int
00604 parse_time2_cb(VALUE m, VALUE hash)
00605 {
00606     VALUE h, min, s, f, p;
00607 
00608     h = rb_reg_nth_match(1, m);
00609     h = str2num(h);
00610 
00611     min = rb_reg_nth_match(2, m);
00612     if (!NIL_P(min))
00613         min = str2num(min);
00614 
00615     s = rb_reg_nth_match(3, m);
00616     if (!NIL_P(s))
00617         s = str2num(s);
00618 
00619     f = rb_reg_nth_match(4, m);
00620 
00621     if (!NIL_P(f))
00622         f = rb_rational_new2(str2num(f),
00623                              f_expt(INT2FIX(10), LONG2NUM(RSTRING_LEN(f))));
00624 
00625     p = rb_reg_nth_match(5, m);
00626 
00627     if (!NIL_P(p)) {
00628         int ih = NUM2INT(h);
00629         ih %= 12;
00630         if (*RSTRING_PTR(p) == 'P' || *RSTRING_PTR(p) == 'p')
00631             ih += 12;
00632         h = INT2FIX(ih);
00633     }
00634 
00635     set_hash("hour", h);
00636     if (!NIL_P(min))
00637         set_hash("min", min);
00638     if (!NIL_P(s))
00639         set_hash("sec", s);
00640     if (!NIL_P(f))
00641         set_hash("sec_fraction", f);
00642 
00643     return 1;
00644 }
00645 
00646 static int
00647 parse_time_cb(VALUE m, VALUE hash)
00648 {
00649     static const char pat_source[] =
00650             "\\A(\\d+)h?"
00651               "(?:\\s*:?\\s*(\\d+)m?"
00652                 "(?:"
00653                   "\\s*:?\\s*(\\d+)(?:[,.](\\d+))?s?"
00654                 ")?"
00655               ")?"
00656             "(?:\\s*([ap])(?:m\\b|\\.m\\.))?";
00657     static VALUE pat = Qnil;
00658     VALUE s1, s2;
00659 
00660     s1 = rb_reg_nth_match(1, m);
00661     s2 = rb_reg_nth_match(2, m);
00662 
00663     if (!NIL_P(s2))
00664         set_hash("zone", s2);
00665 
00666     REGCOMP_I(pat);
00667 
00668     {
00669         VALUE m = f_match(pat, s1);
00670 
00671         if (NIL_P(m))
00672             return 0;
00673         parse_time2_cb(m, hash);
00674     }
00675 
00676     return 1;
00677 }
00678 
00679 static int
00680 parse_time(VALUE str, VALUE hash)
00681 {
00682     static const char pat_source[] =
00683                 "("
00684                    "(?:"
00685                      "\\d+\\s*:\\s*\\d+"
00686                      "(?:"
00687                        "\\s*:\\s*\\d+(?:[,.]\\d*)?"
00688                      ")?"
00689                    "|"
00690                      "\\d+\\s*h(?:\\s*\\d+m?(?:\\s*\\d+s?)?)?"
00691                    ")"
00692                    "(?:"
00693                      "\\s*"
00694                      "[ap](?:m\\b|\\.m\\.)"
00695                    ")?"
00696                  "|"
00697                    "\\d+\\s*[ap](?:m\\b|\\.m\\.)"
00698                  ")"
00699                  "(?:"
00700                    "\\s*"
00701                    "("
00702                      "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?"
00703                    "|"
00704                      "[[:alpha:].\\s]+(?:standard|daylight)\\stime\\b"
00705                    "|"
00706                      "[[:alpha:]]+(?:\\sdst)?\\b"
00707                    ")"
00708                 ")?";
00709     static VALUE pat = Qnil;
00710 
00711     REGCOMP_I(pat);
00712     SUBS(str, pat, parse_time_cb);
00713 }
00714 
00715 static int
00716 parse_eu_cb(VALUE m, VALUE hash)
00717 {
00718     VALUE y, mon, d, b;
00719 
00720     d = rb_reg_nth_match(1, m);
00721     mon = rb_reg_nth_match(2, m);
00722     b = rb_reg_nth_match(3, m);
00723     y = rb_reg_nth_match(4, m);
00724 
00725     mon = INT2FIX(mon_num(mon));
00726 
00727     s3e(hash, y, mon, d, !NIL_P(b) &&
00728         (*RSTRING_PTR(b) == 'B' ||
00729          *RSTRING_PTR(b) == 'b'));
00730     return 1;
00731 }
00732 
00733 static int
00734 parse_eu(VALUE str, VALUE hash)
00735 {
00736     static const char pat_source[] =
00737                 "'?(\\d+)[^-\\d\\s]*"
00738                  "\\s*"
00739                  "(" ABBR_MONTHS ")[^-\\d\\s']*"
00740                  "(?:"
00741                    "\\s*"
00742                    "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?"
00743                    "\\s*"
00744                    "('?-?\\d+(?:(?:st|nd|rd|th)\\b)?)"
00745                 ")?";
00746     static VALUE pat = Qnil;
00747 
00748     REGCOMP_I(pat);
00749     SUBS(str, pat, parse_eu_cb);
00750 }
00751 
00752 static int
00753 parse_us_cb(VALUE m, VALUE hash)
00754 {
00755     VALUE y, mon, d, b;
00756 
00757     mon = rb_reg_nth_match(1, m);
00758     d = rb_reg_nth_match(2, m);
00759     b = rb_reg_nth_match(3, m);
00760     y = rb_reg_nth_match(4, m);
00761 
00762     mon = INT2FIX(mon_num(mon));
00763 
00764     s3e(hash, y, mon, d, !NIL_P(b) &&
00765         (*RSTRING_PTR(b) == 'B' ||
00766          *RSTRING_PTR(b) == 'b'));
00767     return 1;
00768 }
00769 
00770 static int
00771 parse_us(VALUE str, VALUE hash)
00772 {
00773     static const char pat_source[] =
00774                 "\\b(" ABBR_MONTHS ")[^-\\d\\s']*"
00775                  "\\s*"
00776                  "('?\\d+)[^-\\d\\s']*"
00777                  "(?:"
00778                    "\\s*"
00779                    "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?"
00780                    "\\s*"
00781                    "('?-?\\d+)"
00782                 ")?";
00783     static VALUE pat = Qnil;
00784 
00785     REGCOMP_I(pat);
00786     SUBS(str, pat, parse_us_cb);
00787 }
00788 
00789 static int
00790 parse_iso_cb(VALUE m, VALUE hash)
00791 {
00792     VALUE y, mon, d;
00793 
00794     y = rb_reg_nth_match(1, m);
00795     mon = rb_reg_nth_match(2, m);
00796     d = rb_reg_nth_match(3, m);
00797 
00798     s3e(hash, y, mon, d, 0);
00799     return 1;
00800 }
00801 
00802 static int
00803 parse_iso(VALUE str, VALUE hash)
00804 {
00805     static const char pat_source[] = "('?[-+]?\\d+)-(\\d+)-('?-?\\d+)";
00806     static VALUE pat = Qnil;
00807 
00808     REGCOMP_0(pat);
00809     SUBS(str, pat, parse_iso_cb);
00810 }
00811 
00812 static int
00813 parse_iso21_cb(VALUE m, VALUE hash)
00814 {
00815     VALUE y, w, d;
00816 
00817     y = rb_reg_nth_match(1, m);
00818     w = rb_reg_nth_match(2, m);
00819     d = rb_reg_nth_match(3, m);
00820 
00821     if (!NIL_P(y))
00822         set_hash("cwyear", str2num(y));
00823     set_hash("cweek", str2num(w));
00824     if (!NIL_P(d))
00825         set_hash("cwday", str2num(d));
00826 
00827     return 1;
00828 }
00829 
00830 static int
00831 parse_iso21(VALUE str, VALUE hash)
00832 {
00833     static const char pat_source[] =
00834         "\\b(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?\\b";
00835     static VALUE pat = Qnil;
00836 
00837     REGCOMP_I(pat);
00838     SUBS(str, pat, parse_iso21_cb);
00839 }
00840 
00841 static int
00842 parse_iso22_cb(VALUE m, VALUE hash)
00843 {
00844     VALUE d;
00845 
00846     d = rb_reg_nth_match(1, m);
00847     set_hash("cwday", str2num(d));
00848     return 1;
00849 }
00850 
00851 static int
00852 parse_iso22(VALUE str, VALUE hash)
00853 {
00854     static const char pat_source[] = "-w-(\\d)\\b";
00855     static VALUE pat = Qnil;
00856 
00857     REGCOMP_I(pat);
00858     SUBS(str, pat, parse_iso22_cb);
00859 }
00860 
00861 static int
00862 parse_iso23_cb(VALUE m, VALUE hash)
00863 {
00864     VALUE mon, d;
00865 
00866     mon = rb_reg_nth_match(1, m);
00867     d = rb_reg_nth_match(2, m);
00868 
00869     if (!NIL_P(mon))
00870         set_hash("mon", str2num(mon));
00871     set_hash("mday", str2num(d));
00872 
00873     return 1;
00874 }
00875 
00876 static int
00877 parse_iso23(VALUE str, VALUE hash)
00878 {
00879     static const char pat_source[] = "--(\\d{2})?-(\\d{2})\\b";
00880     static VALUE pat = Qnil;
00881 
00882     REGCOMP_0(pat);
00883     SUBS(str, pat, parse_iso23_cb);
00884 }
00885 
00886 static int
00887 parse_iso24_cb(VALUE m, VALUE hash)
00888 {
00889     VALUE mon, d;
00890 
00891     mon = rb_reg_nth_match(1, m);
00892     d = rb_reg_nth_match(2, m);
00893 
00894     set_hash("mon", str2num(mon));
00895     if (!NIL_P(d))
00896         set_hash("mday", str2num(d));
00897 
00898     return 1;
00899 }
00900 
00901 static int
00902 parse_iso24(VALUE str, VALUE hash)
00903 {
00904     static const char pat_source[] = "--(\\d{2})(\\d{2})?\\b";
00905     static VALUE pat = Qnil;
00906 
00907     REGCOMP_0(pat);
00908     SUBS(str, pat, parse_iso24_cb);
00909 }
00910 
00911 static int
00912 parse_iso25_cb(VALUE m, VALUE hash)
00913 {
00914     VALUE y, d;
00915 
00916     y = rb_reg_nth_match(1, m);
00917     d = rb_reg_nth_match(2, m);
00918 
00919     set_hash("year", str2num(y));
00920     set_hash("yday", str2num(d));
00921 
00922     return 1;
00923 }
00924 
00925 static int
00926 parse_iso25(VALUE str, VALUE hash)
00927 {
00928     static const char pat0_source[] = "[,.](\\d{2}|\\d{4})-\\d{3}\\b";
00929     static VALUE pat0 = Qnil;
00930     static const char pat_source[] = "\\b(\\d{2}|\\d{4})-(\\d{3})\\b";
00931     static VALUE pat = Qnil;
00932 
00933     REGCOMP_0(pat0);
00934     REGCOMP_0(pat);
00935 
00936     if (!NIL_P(f_match(pat0, str)))
00937         return 0;
00938     SUBS(str, pat, parse_iso25_cb);
00939 }
00940 
00941 static int
00942 parse_iso26_cb(VALUE m, VALUE hash)
00943 {
00944     VALUE d;
00945 
00946     d = rb_reg_nth_match(1, m);
00947     set_hash("yday", str2num(d));
00948 
00949     return 1;
00950 }
00951 static int
00952 parse_iso26(VALUE str, VALUE hash)
00953 {
00954     static const char pat0_source[] = "\\d-\\d{3}\\b";
00955     static VALUE pat0 = Qnil;
00956     static const char pat_source[] = "\\b-(\\d{3})\\b";
00957     static VALUE pat = Qnil;
00958 
00959     REGCOMP_0(pat0);
00960     REGCOMP_0(pat);
00961 
00962     if (!NIL_P(f_match(pat0, str)))
00963         return 0;
00964     SUBS(str, pat, parse_iso26_cb);
00965 }
00966 
00967 static int
00968 parse_iso2(VALUE str, VALUE hash)
00969 {
00970     if (parse_iso21(str, hash))
00971         goto ok;
00972     if (parse_iso22(str, hash))
00973         goto ok;
00974     if (parse_iso23(str, hash))
00975         goto ok;
00976     if (parse_iso24(str, hash))
00977         goto ok;
00978     if (parse_iso25(str, hash))
00979         goto ok;
00980     if (parse_iso26(str, hash))
00981         goto ok;
00982     return 0;
00983 
00984   ok:
00985     return 1;
00986 }
00987 
00988 static int
00989 gengo(int c)
00990 {
00991     int e;
00992 
00993     switch (c) {
00994       case 'M': case 'm': e = 1867; break;
00995       case 'T': case 't': e = 1911; break;
00996       case 'S': case 's': e = 1925; break;
00997       case 'H': case 'h': e = 1988; break;
00998       default:  e = 0; break;
00999     }
01000     return e;
01001 }
01002 
01003 static int
01004 parse_jis_cb(VALUE m, VALUE hash)
01005 {
01006     VALUE e, y, mon, d;
01007     int ep;
01008 
01009     e = rb_reg_nth_match(1, m);
01010     y = rb_reg_nth_match(2, m);
01011     mon = rb_reg_nth_match(3, m);
01012     d = rb_reg_nth_match(4, m);
01013 
01014     ep = gengo(*RSTRING_PTR(e));
01015 
01016     set_hash("year", f_add(str2num(y), INT2FIX(ep)));
01017     set_hash("mon", str2num(mon));
01018     set_hash("mday", str2num(d));
01019 
01020     return 1;
01021 }
01022 
01023 static int
01024 parse_jis(VALUE str, VALUE hash)
01025 {
01026     static const char pat_source[] = "\\b([mtsh])(\\d+)\\.(\\d+)\\.(\\d+)";
01027     static VALUE pat = Qnil;
01028 
01029     REGCOMP_I(pat);
01030     SUBS(str, pat, parse_jis_cb);
01031 }
01032 
01033 static int
01034 parse_vms11_cb(VALUE m, VALUE hash)
01035 {
01036     VALUE y, mon, d;
01037 
01038     d = rb_reg_nth_match(1, m);
01039     mon = rb_reg_nth_match(2, m);
01040     y = rb_reg_nth_match(3, m);
01041 
01042     mon = INT2FIX(mon_num(mon));
01043 
01044     s3e(hash, y, mon, d, 0);
01045     return 1;
01046 }
01047 
01048 static int
01049 parse_vms11(VALUE str, VALUE hash)
01050 {
01051     static const char pat_source[] =
01052         "('?-?\\d+)-(" ABBR_MONTHS ")[^-]*"
01053         "-('?-?\\d+)";
01054     static VALUE pat = Qnil;
01055 
01056     REGCOMP_I(pat);
01057     SUBS(str, pat, parse_vms11_cb);
01058 }
01059 
01060 static int
01061 parse_vms12_cb(VALUE m, VALUE hash)
01062 {
01063     VALUE y, mon, d;
01064 
01065     mon = rb_reg_nth_match(1, m);
01066     d = rb_reg_nth_match(2, m);
01067     y = rb_reg_nth_match(3, m);
01068 
01069     mon = INT2FIX(mon_num(mon));
01070 
01071     s3e(hash, y, mon, d, 0);
01072     return 1;
01073 }
01074 
01075 static int
01076 parse_vms12(VALUE str, VALUE hash)
01077 {
01078     static const char pat_source[] =
01079         "\\b(" ABBR_MONTHS ")[^-]*"
01080         "-('?-?\\d+)(?:-('?-?\\d+))?";
01081     static VALUE pat = Qnil;
01082 
01083     REGCOMP_I(pat);
01084     SUBS(str, pat, parse_vms12_cb);
01085 }
01086 
01087 static int
01088 parse_vms(VALUE str, VALUE hash)
01089 {
01090     if (parse_vms11(str, hash))
01091         goto ok;
01092     if (parse_vms12(str, hash))
01093         goto ok;
01094     return 0;
01095 
01096   ok:
01097     return 1;
01098 }
01099 
01100 static int
01101 parse_sla_cb(VALUE m, VALUE hash)
01102 {
01103     VALUE y, mon, d;
01104 
01105     y = rb_reg_nth_match(1, m);
01106     mon = rb_reg_nth_match(2, m);
01107     d = rb_reg_nth_match(3, m);
01108 
01109     s3e(hash, y, mon, d, 0);
01110     return 1;
01111 }
01112 
01113 static int
01114 parse_sla(VALUE str, VALUE hash)
01115 {
01116     static const char pat_source[] =
01117         "('?-?\\d+)/\\s*('?\\d+)(?:\\D\\s*('?-?\\d+))?";
01118     static VALUE pat = Qnil;
01119 
01120     REGCOMP_I(pat);
01121     SUBS(str, pat, parse_sla_cb);
01122 }
01123 
01124 static int
01125 parse_dot_cb(VALUE m, VALUE hash)
01126 {
01127     VALUE y, mon, d;
01128 
01129     y = rb_reg_nth_match(1, m);
01130     mon = rb_reg_nth_match(2, m);
01131     d = rb_reg_nth_match(3, m);
01132 
01133     s3e(hash, y, mon, d, 0);
01134     return 1;
01135 }
01136 
01137 static int
01138 parse_dot(VALUE str, VALUE hash)
01139 {
01140     static const char pat_source[] =
01141         "('?-?\\d+)\\.\\s*('?\\d+)\\.\\s*('?-?\\d+)";
01142     static VALUE pat = Qnil;
01143 
01144     REGCOMP_I(pat);
01145     SUBS(str, pat, parse_dot_cb);
01146 }
01147 
01148 static int
01149 parse_year_cb(VALUE m, VALUE hash)
01150 {
01151     VALUE y;
01152 
01153     y = rb_reg_nth_match(1, m);
01154     set_hash("year", str2num(y));
01155     return 1;
01156 }
01157 
01158 static int
01159 parse_year(VALUE str, VALUE hash)
01160 {
01161     static const char pat_source[] = "'(\\d+)\\b";
01162     static VALUE pat = Qnil;
01163 
01164     REGCOMP_0(pat);
01165     SUBS(str, pat, parse_year_cb);
01166 }
01167 
01168 static int
01169 parse_mon_cb(VALUE m, VALUE hash)
01170 {
01171     VALUE mon;
01172 
01173     mon = rb_reg_nth_match(1, m);
01174     set_hash("mon", INT2FIX(mon_num(mon)));
01175     return 1;
01176 }
01177 
01178 static int
01179 parse_mon(VALUE str, VALUE hash)
01180 {
01181     static const char pat_source[] = "\\b(" ABBR_MONTHS ")\\S*";
01182     static VALUE pat = Qnil;
01183 
01184     REGCOMP_I(pat);
01185     SUBS(str, pat, parse_mon_cb);
01186 }
01187 
01188 static int
01189 parse_mday_cb(VALUE m, VALUE hash)
01190 {
01191     VALUE d;
01192 
01193     d = rb_reg_nth_match(1, m);
01194     set_hash("mday", str2num(d));
01195     return 1;
01196 }
01197 
01198 static int
01199 parse_mday(VALUE str, VALUE hash)
01200 {
01201     static const char pat_source[] = "(\\d+)(st|nd|rd|th)\\b";
01202     static VALUE pat = Qnil;
01203 
01204     REGCOMP_I(pat);
01205     SUBS(str, pat, parse_mday_cb);
01206 }
01207 
01208 static int
01209 n2i(const char *s, long f, long w)
01210 {
01211     long e, i;
01212     int v;
01213 
01214     e = f + w;
01215     v = 0;
01216     for (i = f; i < e; i++) {
01217         v *= 10;
01218         v += s[i] - '0';
01219     }
01220     return v;
01221 }
01222 
01223 static int
01224 parse_ddd_cb(VALUE m, VALUE hash)
01225 {
01226     VALUE s1, s2, s3, s4, s5;
01227     const char *cs2, *cs3, *cs5;
01228     long l2, l3, l4, l5;
01229 
01230     s1 = rb_reg_nth_match(1, m);
01231     s2 = rb_reg_nth_match(2, m);
01232     s3 = rb_reg_nth_match(3, m);
01233     s4 = rb_reg_nth_match(4, m);
01234     s5 = rb_reg_nth_match(5, m);
01235 
01236     cs2 = RSTRING_PTR(s2);
01237     l2 = RSTRING_LEN(s2);
01238 
01239     switch (l2) {
01240       case 2:
01241         if (NIL_P(s3) && !NIL_P(s4))
01242             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01243         else
01244             set_hash("mday", INT2FIX(n2i(cs2,    0, 2)));
01245         break;
01246       case 4:
01247         if (NIL_P(s3) && !NIL_P(s4)) {
01248             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01249             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01250         }
01251         else {
01252             set_hash("mon",  INT2FIX(n2i(cs2,    0, 2)));
01253             set_hash("mday", INT2FIX(n2i(cs2,    2, 2)));
01254         }
01255         break;
01256       case 6:
01257         if (NIL_P(s3) && !NIL_P(s4)) {
01258             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01259             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01260             set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
01261         }
01262         else {
01263             int                  y = n2i(cs2,    0, 2);
01264             if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01265                 y = -y;
01266             set_hash("year", INT2FIX(y));
01267             set_hash("mon",  INT2FIX(n2i(cs2,    2, 2)));
01268             set_hash("mday", INT2FIX(n2i(cs2,    4, 2)));
01269         }
01270         break;
01271       case 8:
01272       case 10:
01273       case 12:
01274       case 14:
01275         if (NIL_P(s3) && !NIL_P(s4)) {
01276             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01277             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01278             set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
01279             set_hash("mday", INT2FIX(n2i(cs2, l2-8, 2)));
01280             if (l2 >= 10)
01281                 set_hash("mon", INT2FIX(n2i(cs2, l2-10, 2)));
01282             if (l2 == 12) {
01283                 int y = n2i(cs2, l2-12, 2);
01284                 if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01285                     y = -y;
01286                 set_hash("year", INT2FIX(y));
01287             }
01288             if (l2 == 14) {
01289                 int y = n2i(cs2, l2-14, 4);
01290                 if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01291                     y = -y;
01292                 set_hash("year", INT2FIX(y));
01293                 set_hash("_comp", Qfalse);
01294             }
01295         }
01296         else {
01297             int                  y = n2i(cs2,    0, 4);
01298             if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01299                 y = -y;
01300             set_hash("year", INT2FIX(y));
01301             set_hash("mon",  INT2FIX(n2i(cs2,    4, 2)));
01302             set_hash("mday", INT2FIX(n2i(cs2,    6, 2)));
01303             if (l2 >= 10)
01304                 set_hash("hour", INT2FIX(n2i(cs2,    8, 2)));
01305             if (l2 >= 12)
01306                 set_hash("min",  INT2FIX(n2i(cs2,   10, 2)));
01307             if (l2 >= 14)
01308                 set_hash("sec",  INT2FIX(n2i(cs2,   12, 2)));
01309             set_hash("_comp", Qfalse);
01310         }
01311         break;
01312       case 3:
01313         if (NIL_P(s3) && !NIL_P(s4)) {
01314             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01315             set_hash("min",  INT2FIX(n2i(cs2, l2-3, 1)));
01316         }
01317         else
01318             set_hash("yday", INT2FIX(n2i(cs2,    0, 3)));
01319         break;
01320       case 5:
01321         if (NIL_P(s3) && !NIL_P(s4)) {
01322             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01323             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01324             set_hash("hour", INT2FIX(n2i(cs2, l2-5, 1)));
01325         }
01326         else {
01327             int                  y = n2i(cs2,    0, 2);
01328             if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01329                 y = -y;
01330             set_hash("year", INT2FIX(y));
01331             set_hash("yday", INT2FIX(n2i(cs2,    2, 3)));
01332         }
01333         break;
01334       case 7:
01335         if (NIL_P(s3) && !NIL_P(s4)) {
01336             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01337             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01338             set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
01339             set_hash("mday", INT2FIX(n2i(cs2, l2-7, 1)));
01340         }
01341         else {
01342             int                  y = n2i(cs2,    0, 4);
01343             if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01344                 y = -y;
01345             set_hash("year", INT2FIX(y));
01346             set_hash("yday", INT2FIX(n2i(cs2,    4, 3)));
01347         }
01348         break;
01349     }
01350     RB_GC_GUARD(s2);
01351     if (!NIL_P(s3)) {
01352         cs3 = RSTRING_PTR(s3);
01353         l3 = RSTRING_LEN(s3);
01354 
01355         if (!NIL_P(s4)) {
01356             switch (l3) {
01357               case 2:
01358               case 4:
01359               case 6:
01360                 set_hash("sec", INT2FIX(n2i(cs3, l3-2, 2)));
01361                 if (l3 >= 4)
01362                     set_hash("min", INT2FIX(n2i(cs3, l3-4, 2)));
01363                 if (l3 >= 6)
01364                     set_hash("hour", INT2FIX(n2i(cs3, l3-6, 2)));
01365                 break;
01366             }
01367         }
01368         else {
01369             switch (l3) {
01370               case 2:
01371               case 4:
01372               case 6:
01373                 set_hash("hour", INT2FIX(n2i(cs3, 0, 2)));
01374                 if (l3 >= 4)
01375                     set_hash("min", INT2FIX(n2i(cs3, 2, 2)));
01376                 if (l3 >= 6)
01377                     set_hash("sec", INT2FIX(n2i(cs3, 4, 2)));
01378                 break;
01379             }
01380         }
01381         RB_GC_GUARD(s3);
01382     }
01383     if (!NIL_P(s4)) {
01384         l4 = RSTRING_LEN(s4);
01385 
01386         set_hash("sec_fraction",
01387                  rb_rational_new2(str2num(s4),
01388                                   f_expt(INT2FIX(10), LONG2NUM(l4))));
01389     }
01390     if (!NIL_P(s5)) {
01391         cs5 = RSTRING_PTR(s5);
01392         l5 = RSTRING_LEN(s5);
01393 
01394         set_hash("zone", s5);
01395 
01396         if (*cs5 == '[') {
01397             char *buf = ALLOCA_N(char, l5 + 1);
01398             char *s1, *s2, *s3;
01399             VALUE zone;
01400 
01401             memcpy(buf, cs5, l5);
01402             buf[l5 - 1] = '\0';
01403 
01404             s1 = buf + 1;
01405             s2 = strchr(buf, ':');
01406             if (s2) {
01407                 *s2 = '\0';
01408                 s2++;
01409             }
01410             if (s2)
01411                 s3 = s2;
01412             else
01413                 s3 = s1;
01414             zone = rb_str_new2(s3);
01415             set_hash("zone", zone);
01416             if (isdigit(*s1))
01417                 *--s1 = '+';
01418             set_hash("offset", date_zone_to_diff(rb_str_new2(s1)));
01419         }
01420         RB_GC_GUARD(s5);
01421     }
01422 
01423     return 1;
01424 }
01425 
01426 static int
01427 parse_ddd(VALUE str, VALUE hash)
01428 {
01429     static const char pat_source[] =
01430                 "([-+]?)(\\d{2,14})"
01431                   "(?:"
01432                     "\\s*"
01433                     "t?"
01434                     "\\s*"
01435                     "(\\d{2,6})?(?:[,.](\\d*))?"
01436                   ")?"
01437                   "(?:"
01438                     "\\s*"
01439                     "("
01440                       "z\\b"
01441                     "|"
01442                       "[-+]\\d{1,4}\\b"
01443                     "|"
01444                       "\\[[-+]?\\d[^\\]]*\\]"
01445                     ")"
01446                 ")?";
01447     static VALUE pat = Qnil;
01448 
01449     REGCOMP_I(pat);
01450     SUBS(str, pat, parse_ddd_cb);
01451 }
01452 
01453 static int
01454 parse_bc_cb(VALUE m, VALUE hash)
01455 {
01456     VALUE y;
01457 
01458     y = ref_hash("year");
01459     if (!NIL_P(y))
01460         set_hash("year", f_add(f_negate(y), INT2FIX(1)));
01461 
01462     return 1;
01463 }
01464 
01465 static int
01466 parse_bc(VALUE str, VALUE hash)
01467 {
01468     static const char pat_source[] =
01469         "\\b(bc\\b|bce\\b|b\\.c\\.|b\\.c\\.e\\.)";
01470     static VALUE pat = Qnil;
01471 
01472     REGCOMP_I(pat);
01473     SUBS(str, pat, parse_bc_cb);
01474 }
01475 
01476 static int
01477 parse_frag_cb(VALUE m, VALUE hash)
01478 {
01479     VALUE s, n;
01480 
01481     s = rb_reg_nth_match(1, m);
01482 
01483     if (!NIL_P(ref_hash("hour")) && NIL_P(ref_hash("mday"))) {
01484         n = str2num(s);
01485         if (f_ge_p(n, INT2FIX(1)) &&
01486             f_le_p(n, INT2FIX(31)))
01487             set_hash("mday", n);
01488     }
01489     if (!NIL_P(ref_hash("mday")) && NIL_P(ref_hash("hour"))) {
01490         n = str2num(s);
01491         if (f_ge_p(n, INT2FIX(0)) &&
01492             f_le_p(n, INT2FIX(24)))
01493             set_hash("hour", n);
01494     }
01495 
01496     return 1;
01497 }
01498 
01499 static int
01500 parse_frag(VALUE str, VALUE hash)
01501 {
01502     static const char pat_source[] = "\\A\\s*(\\d{1,2})\\s*\\z";
01503     static VALUE pat = Qnil;
01504 
01505     REGCOMP_I(pat);
01506     SUBS(str, pat, parse_frag_cb);
01507 }
01508 
01509 #define HAVE_ALPHA (1<<0)
01510 #define HAVE_DIGIT (1<<1)
01511 #define HAVE_DASH (1<<2)
01512 #define HAVE_DOT (1<<3)
01513 #define HAVE_SLASH (1<<4)
01514 
01515 static unsigned
01516 check_class(VALUE s)
01517 {
01518     unsigned flags;
01519     long i;
01520 
01521     flags = 0;
01522     for (i = 0; i < RSTRING_LEN(s); i++) {
01523         if (isalpha(RSTRING_PTR(s)[i]))
01524             flags |= HAVE_ALPHA;
01525         if (isdigit(RSTRING_PTR(s)[i]))
01526             flags |= HAVE_DIGIT;
01527         if (RSTRING_PTR(s)[i] == '-')
01528             flags |= HAVE_DASH;
01529         if (RSTRING_PTR(s)[i] == '.')
01530             flags |= HAVE_DOT;
01531         if (RSTRING_PTR(s)[i] == '/')
01532             flags |= HAVE_SLASH;
01533     }
01534     return flags;
01535 }
01536 
01537 #define HAVE_ELEM_P(x) ((check_class(str) & (x)) == (x))
01538 
01539 VALUE
01540 date__parse(VALUE str, VALUE comp)
01541 {
01542     VALUE backref, hash;
01543 
01544     backref = rb_backref_get();
01545     rb_match_busy(backref);
01546 
01547     {
01548         static const char pat_source[] = "[^-+',./:@[:alnum:]\\[\\]]+";
01549         static VALUE pat = Qnil;
01550 
01551         REGCOMP_0(pat);
01552         str = rb_str_dup(str);
01553         f_gsub_bang(str, pat, asp_string());
01554     }
01555 
01556     hash = rb_hash_new();
01557     set_hash("_comp", comp);
01558 
01559     if (HAVE_ELEM_P(HAVE_ALPHA))
01560         parse_day(str, hash);
01561     if (HAVE_ELEM_P(HAVE_DIGIT))
01562         parse_time(str, hash);
01563 
01564     if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT))
01565         if (parse_eu(str, hash))
01566             goto ok;
01567     if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT))
01568         if (parse_us(str, hash))
01569             goto ok;
01570     if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DASH))
01571         if (parse_iso(str, hash))
01572             goto ok;
01573     if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DOT))
01574         if (parse_jis(str, hash))
01575             goto ok;
01576     if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_DASH))
01577         if (parse_vms(str, hash))
01578             goto ok;
01579     if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_SLASH))
01580         if (parse_sla(str, hash))
01581             goto ok;
01582     if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DOT))
01583         if (parse_dot(str, hash))
01584             goto ok;
01585     if (HAVE_ELEM_P(HAVE_DIGIT))
01586         if (parse_iso2(str, hash))
01587             goto ok;
01588     if (HAVE_ELEM_P(HAVE_DIGIT))
01589         if (parse_year(str, hash))
01590             goto ok;
01591     if (HAVE_ELEM_P(HAVE_ALPHA))
01592         if (parse_mon(str, hash))
01593             goto ok;
01594     if (HAVE_ELEM_P(HAVE_DIGIT))
01595         if (parse_mday(str, hash))
01596             goto ok;
01597     if (HAVE_ELEM_P(HAVE_DIGIT))
01598         if (parse_ddd(str, hash))
01599             goto ok;
01600 
01601   ok:
01602     if (HAVE_ELEM_P(HAVE_ALPHA))
01603         parse_bc(str, hash);
01604     if (HAVE_ELEM_P(HAVE_DIGIT))
01605         parse_frag(str, hash);
01606 
01607     {
01608         if (RTEST(ref_hash("_comp"))) {
01609             VALUE y;
01610 
01611             y = ref_hash("cwyear");
01612             if (!NIL_P(y))
01613                 if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) {
01614                     if (f_ge_p(y, INT2FIX(69)))
01615                         set_hash("cwyear", f_add(y, INT2FIX(1900)));
01616                     else
01617                         set_hash("cwyear", f_add(y, INT2FIX(2000)));
01618                 }
01619             y = ref_hash("year");
01620             if (!NIL_P(y))
01621                 if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) {
01622                     if (f_ge_p(y, INT2FIX(69)))
01623                         set_hash("year", f_add(y, INT2FIX(1900)));
01624                     else
01625                         set_hash("year", f_add(y, INT2FIX(2000)));
01626                 }
01627         }
01628     }
01629 
01630     del_hash("_comp");
01631 
01632     {
01633         VALUE zone = ref_hash("zone");
01634         if (!NIL_P(zone) && NIL_P(ref_hash("offset")))
01635             set_hash("offset", date_zone_to_diff(zone));
01636     }
01637 
01638     rb_backref_set(backref);
01639 
01640     return hash;
01641 }
01642 
01643 static VALUE
01644 comp_year69(VALUE y)
01645 {
01646     if (f_ge_p(y, INT2FIX(69)))
01647         return f_add(y, INT2FIX(1900));
01648     return f_add(y, INT2FIX(2000));
01649 }
01650 
01651 static VALUE
01652 comp_year50(VALUE y)
01653 {
01654     if (f_ge_p(y, INT2FIX(50)))
01655         return f_add(y, INT2FIX(1900));
01656     return f_add(y, INT2FIX(2000));
01657 }
01658 
01659 static VALUE
01660 sec_fraction(VALUE f)
01661 {
01662     return rb_rational_new2(str2num(f),
01663                             f_expt(INT2FIX(10),
01664                                    LONG2NUM(RSTRING_LEN(f))));
01665 }
01666 
01667 #define SNUM 14
01668 
01669 static int
01670 iso8601_ext_datetime_cb(VALUE m, VALUE hash)
01671 {
01672     VALUE s[SNUM + 1], y;
01673 
01674     {
01675         int i;
01676         s[0] = Qnil;
01677         for (i = 1; i <= SNUM; i++)
01678             s[i] = rb_reg_nth_match(i, m);
01679     }
01680 
01681     if (!NIL_P(s[3])) {
01682         set_hash("mday", str2num(s[3]));
01683         if (strcmp(RSTRING_PTR(s[1]), "-") != 0) {
01684             y = str2num(s[1]);
01685             if (RSTRING_LEN(s[1]) < 4)
01686                 y = comp_year69(y);
01687             set_hash("year", y);
01688         }
01689         if (NIL_P(s[2])) {
01690             if (strcmp(RSTRING_PTR(s[1]), "-") != 0)
01691                 return 0;
01692         }
01693         else
01694             set_hash("mon", str2num(s[2]));
01695     }
01696     else if (!NIL_P(s[5])) {
01697         set_hash("yday", str2num(s[5]));
01698         if (!NIL_P(s[4])) {
01699             y = str2num(s[4]);
01700             if (RSTRING_LEN(s[4]) < 4)
01701                 y = comp_year69(y);
01702             set_hash("year", y);
01703         }
01704     }
01705     else if (!NIL_P(s[8])) {
01706         set_hash("cweek", str2num(s[7]));
01707         set_hash("cwday", str2num(s[8]));
01708         if (!NIL_P(s[6])) {
01709             y = str2num(s[6]);
01710             if (RSTRING_LEN(s[6]) < 4)
01711                 y = comp_year69(y);
01712             set_hash("cwyear", y);
01713         }
01714     }
01715     else if (!NIL_P(s[9])) {
01716         set_hash("cwday", str2num(s[9]));
01717     }
01718     if (!NIL_P(s[10])) {
01719         set_hash("hour", str2num(s[10]));
01720         set_hash("min", str2num(s[11]));
01721         if (!NIL_P(s[12]))
01722             set_hash("sec", str2num(s[12]));
01723     }
01724     if (!NIL_P(s[13])) {
01725         set_hash("sec_fraction", sec_fraction(s[13]));
01726     }
01727     if (!NIL_P(s[14])) {
01728         set_hash("zone", s[14]);
01729         set_hash("offset", date_zone_to_diff(s[14]));
01730     }
01731 
01732     return 1;
01733 }
01734 
01735 static int
01736 iso8601_ext_datetime(VALUE str, VALUE hash)
01737 {
01738     static const char pat_source[] =
01739         "\\A\\s*(?:([-+]?\\d{2,}|-)-(\\d{2})?-(\\d{2})|"
01740                 "([-+]?\\d{2,})?-(\\d{3})|"
01741                 "(\\d{4}|\\d{2})?-w(\\d{2})-(\\d)|"
01742                 "-w-(\\d))"
01743         "(?:t"
01744         "(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?)?"
01745         "(z|[-+]\\d{2}(?::?\\d{2})?)?)?\\s*\\z";
01746     static VALUE pat = Qnil;
01747 
01748     REGCOMP_I(pat);
01749     MATCH(str, pat, iso8601_ext_datetime_cb);
01750 }
01751 
01752 #undef SNUM
01753 #define SNUM 17
01754 
01755 static int
01756 iso8601_bas_datetime_cb(VALUE m, VALUE hash)
01757 {
01758     VALUE s[SNUM + 1], y;
01759 
01760     {
01761         int i;
01762         s[0] = Qnil;
01763         for (i = 1; i <= SNUM; i++)
01764             s[i] = rb_reg_nth_match(i, m);
01765     }
01766 
01767     if (!NIL_P(s[3])) {
01768         set_hash("mday", str2num(s[3]));
01769         if (strcmp(RSTRING_PTR(s[1]), "--") != 0) {
01770             y = str2num(s[1]);
01771             if (RSTRING_LEN(s[1]) < 4)
01772                 y = comp_year69(y);
01773             set_hash("year", y);
01774         }
01775         if (*RSTRING_PTR(s[2]) == '-') {
01776             if (strcmp(RSTRING_PTR(s[1]), "--") != 0)
01777                 return 0;
01778         }
01779         else
01780             set_hash("mon", str2num(s[2]));
01781     }
01782     else if (!NIL_P(s[5])) {
01783         set_hash("yday", str2num(s[5]));
01784         y = str2num(s[4]);
01785         if (RSTRING_LEN(s[4]) < 4)
01786             y = comp_year69(y);
01787         set_hash("year", y);
01788     }
01789     else if (!NIL_P(s[6])) {
01790         set_hash("yday", str2num(s[6]));
01791     }
01792     else if (!NIL_P(s[9])) {
01793         set_hash("cweek", str2num(s[8]));
01794         set_hash("cwday", str2num(s[9]));
01795         y = str2num(s[7]);
01796         if (RSTRING_LEN(s[7]) < 4)
01797             y = comp_year69(y);
01798         set_hash("cwyear", y);
01799     }
01800     else if (!NIL_P(s[11])) {
01801         set_hash("cweek", str2num(s[10]));
01802         set_hash("cwday", str2num(s[11]));
01803     }
01804     else if (!NIL_P(s[12])) {
01805         set_hash("cwday", str2num(s[12]));
01806     }
01807     if (!NIL_P(s[13])) {
01808         set_hash("hour", str2num(s[13]));
01809         set_hash("min", str2num(s[14]));
01810         if (!NIL_P(s[15]))
01811             set_hash("sec", str2num(s[15]));
01812     }
01813     if (!NIL_P(s[16])) {
01814         set_hash("sec_fraction", sec_fraction(s[16]));
01815     }
01816     if (!NIL_P(s[17])) {
01817         set_hash("zone", s[17]);
01818         set_hash("offset", date_zone_to_diff(s[17]));
01819     }
01820 
01821     return 1;
01822 }
01823 
01824 static int
01825 iso8601_bas_datetime(VALUE str, VALUE hash)
01826 {
01827     static const char pat_source[] =
01828         "\\A\\s*(?:([-+]?(?:\\d{4}|\\d{2})|--)(\\d{2}|-)(\\d{2})|"
01829                    "([-+]?(?:\\d{4}|\\d{2}))(\\d{3})|"
01830                    "-(\\d{3})|"
01831                    "(\\d{4}|\\d{2})w(\\d{2})(\\d)|"
01832                    "-w(\\d{2})(\\d)|"
01833                    "-w-(\\d))"
01834         "(?:t?"
01835         "(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?)?"
01836         "(z|[-+]\\d{2}(?:\\d{2})?)?)?\\s*\\z";
01837     static VALUE pat = Qnil;
01838 
01839     REGCOMP_I(pat);
01840     MATCH(str, pat, iso8601_bas_datetime_cb);
01841 }
01842 
01843 #undef SNUM
01844 #define SNUM 5
01845 
01846 static int
01847 iso8601_ext_time_cb(VALUE m, VALUE hash)
01848 {
01849     VALUE s[SNUM + 1];
01850 
01851     {
01852         int i;
01853         s[0] = Qnil;
01854         for (i = 1; i <= SNUM; i++)
01855             s[i] = rb_reg_nth_match(i, m);
01856     }
01857 
01858     set_hash("hour", str2num(s[1]));
01859     set_hash("min", str2num(s[2]));
01860     if (!NIL_P(s[3]))
01861         set_hash("sec", str2num(s[3]));
01862     if (!NIL_P(s[4]))
01863         set_hash("sec_fraction", sec_fraction(s[4]));
01864     if (!NIL_P(s[5])) {
01865         set_hash("zone", s[5]);
01866         set_hash("offset", date_zone_to_diff(s[5]));
01867     }
01868 
01869     return 1;
01870 }
01871 
01872 #define iso8601_bas_time_cb iso8601_ext_time_cb
01873 
01874 static int
01875 iso8601_ext_time(VALUE str, VALUE hash)
01876 {
01877     static const char pat_source[] =
01878         "\\A\\s*(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?)?"
01879         "(z|[-+]\\d{2}(:?\\d{2})?)?)?\\s*\\z";
01880     static VALUE pat = Qnil;
01881 
01882     REGCOMP_I(pat);
01883     MATCH(str, pat, iso8601_ext_time_cb);
01884 }
01885 
01886 static int
01887 iso8601_bas_time(VALUE str, VALUE hash)
01888 {
01889     static const char pat_source[] =
01890         "\\A\\s*(?:(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?)?"
01891         "(z|[-+]\\d{2}(\\d{2})?)?)?\\s*\\z";
01892     static VALUE pat = Qnil;
01893 
01894     REGCOMP_I(pat);
01895     MATCH(str, pat, iso8601_bas_time_cb);
01896 }
01897 
01898 VALUE
01899 date__iso8601(VALUE str)
01900 {
01901     VALUE backref, hash;
01902 
01903     backref = rb_backref_get();
01904     rb_match_busy(backref);
01905 
01906     hash = rb_hash_new();
01907 
01908     if (iso8601_ext_datetime(str, hash))
01909         goto ok;
01910     if (iso8601_bas_datetime(str, hash))
01911         goto ok;
01912     if (iso8601_ext_time(str, hash))
01913         goto ok;
01914     if (iso8601_bas_time(str, hash))
01915         goto ok;
01916 
01917   ok:
01918     rb_backref_set(backref);
01919 
01920     return hash;
01921 }
01922 
01923 #undef SNUM
01924 #define SNUM 8
01925 
01926 static int
01927 rfc3339_cb(VALUE m, VALUE hash)
01928 {
01929     VALUE s[SNUM + 1];
01930 
01931     {
01932         int i;
01933         s[0] = Qnil;
01934         for (i = 1; i <= SNUM; i++)
01935             s[i] = rb_reg_nth_match(i, m);
01936     }
01937 
01938     set_hash("year", str2num(s[1]));
01939     set_hash("mon", str2num(s[2]));
01940     set_hash("mday", str2num(s[3]));
01941     set_hash("hour", str2num(s[4]));
01942     set_hash("min", str2num(s[5]));
01943     set_hash("sec", str2num(s[6]));
01944     set_hash("zone", s[8]);
01945     set_hash("offset", date_zone_to_diff(s[8]));
01946     if (!NIL_P(s[7]))
01947         set_hash("sec_fraction", sec_fraction(s[7]));
01948 
01949     return 1;
01950 }
01951 
01952 static int
01953 rfc3339(VALUE str, VALUE hash)
01954 {
01955     static const char pat_source[] =
01956         "\\A\\s*(-?\\d{4})-(\\d{2})-(\\d{2})"
01957         "(?:t|\\s)"
01958         "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?"
01959         "(z|[-+]\\d{2}:\\d{2})\\s*\\z";
01960     static VALUE pat = Qnil;
01961 
01962     REGCOMP_I(pat);
01963     MATCH(str, pat, rfc3339_cb);
01964 }
01965 
01966 VALUE
01967 date__rfc3339(VALUE str)
01968 {
01969     VALUE backref, hash;
01970 
01971     backref = rb_backref_get();
01972     rb_match_busy(backref);
01973 
01974     hash = rb_hash_new();
01975     rfc3339(str, hash);
01976     rb_backref_set(backref);
01977     return hash;
01978 }
01979 
01980 #undef SNUM
01981 #define SNUM 8
01982 
01983 static int
01984 xmlschema_datetime_cb(VALUE m, VALUE hash)
01985 {
01986     VALUE s[SNUM + 1];
01987 
01988     {
01989         int i;
01990         s[0] = Qnil;
01991         for (i = 1; i <= SNUM; i++)
01992             s[i] = rb_reg_nth_match(i, m);
01993     }
01994 
01995     set_hash("year", str2num(s[1]));
01996     if (!NIL_P(s[2]))
01997         set_hash("mon", str2num(s[2]));
01998     if (!NIL_P(s[3]))
01999         set_hash("mday", str2num(s[3]));
02000     if (!NIL_P(s[4]))
02001         set_hash("hour", str2num(s[4]));
02002     if (!NIL_P(s[5]))
02003         set_hash("min", str2num(s[5]));
02004     if (!NIL_P(s[6]))
02005         set_hash("sec", str2num(s[6]));
02006     if (!NIL_P(s[7]))
02007         set_hash("sec_fraction", sec_fraction(s[7]));
02008     if (!NIL_P(s[8])) {
02009         set_hash("zone", s[8]);
02010         set_hash("offset", date_zone_to_diff(s[8]));
02011     }
02012 
02013     return 1;
02014 }
02015 
02016 static int
02017 xmlschema_datetime(VALUE str, VALUE hash)
02018 {
02019     static const char pat_source[] =
02020         "\\A\\s*(-?\\d{4,})(?:-(\\d{2})(?:-(\\d{2}))?)?"
02021         "(?:t"
02022           "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?)?"
02023         "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
02024     static VALUE pat = Qnil;
02025 
02026     REGCOMP_I(pat);
02027     MATCH(str, pat, xmlschema_datetime_cb);
02028 }
02029 
02030 #undef SNUM
02031 #define SNUM 5
02032 
02033 static int
02034 xmlschema_time_cb(VALUE m, VALUE hash)
02035 {
02036     VALUE s[SNUM + 1];
02037 
02038     {
02039         int i;
02040         s[0] = Qnil;
02041         for (i = 1; i <= SNUM; i++)
02042             s[i] = rb_reg_nth_match(i, m);
02043     }
02044 
02045     set_hash("hour", str2num(s[1]));
02046     set_hash("min", str2num(s[2]));
02047     if (!NIL_P(s[3]))
02048         set_hash("sec", str2num(s[3]));
02049     if (!NIL_P(s[4]))
02050         set_hash("sec_fraction", sec_fraction(s[4]));
02051     if (!NIL_P(s[5])) {
02052         set_hash("zone", s[5]);
02053         set_hash("offset", date_zone_to_diff(s[5]));
02054     }
02055 
02056     return 1;
02057 }
02058 
02059 static int
02060 xmlschema_time(VALUE str, VALUE hash)
02061 {
02062     static const char pat_source[] =
02063         "\\A\\s*(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?"
02064         "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
02065     static VALUE pat = Qnil;
02066 
02067     REGCOMP_I(pat);
02068     MATCH(str, pat, xmlschema_time_cb);
02069 }
02070 
02071 #undef SNUM
02072 #define SNUM 4
02073 
02074 static int
02075 xmlschema_trunc_cb(VALUE m, VALUE hash)
02076 {
02077     VALUE s[SNUM + 1];
02078 
02079     {
02080         int i;
02081         s[0] = Qnil;
02082         for (i = 1; i <= SNUM; i++)
02083             s[i] = rb_reg_nth_match(i, m);
02084     }
02085 
02086     if (!NIL_P(s[1]))
02087         set_hash("mon", str2num(s[1]));
02088     if (!NIL_P(s[2]))
02089         set_hash("mday", str2num(s[2]));
02090     if (!NIL_P(s[3]))
02091         set_hash("mday", str2num(s[3]));
02092     if (!NIL_P(s[4])) {
02093         set_hash("zone", s[4]);
02094         set_hash("offset", date_zone_to_diff(s[4]));
02095     }
02096 
02097     return 1;
02098 }
02099 
02100 static int
02101 xmlschema_trunc(VALUE str, VALUE hash)
02102 {
02103     static const char pat_source[] =
02104         "\\A\\s*(?:--(\\d{2})(?:-(\\d{2}))?|---(\\d{2}))"
02105         "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
02106     static VALUE pat = Qnil;
02107 
02108     REGCOMP_I(pat);
02109     MATCH(str, pat, xmlschema_trunc_cb);
02110 }
02111 
02112 VALUE
02113 date__xmlschema(VALUE str)
02114 {
02115     VALUE backref, hash;
02116 
02117     backref = rb_backref_get();
02118     rb_match_busy(backref);
02119 
02120     hash = rb_hash_new();
02121 
02122     if (xmlschema_datetime(str, hash))
02123         goto ok;
02124     if (xmlschema_time(str, hash))
02125         goto ok;
02126     if (xmlschema_trunc(str, hash))
02127         goto ok;
02128 
02129   ok:
02130     rb_backref_set(backref);
02131 
02132     return hash;
02133 }
02134 
02135 #undef SNUM
02136 #define SNUM 8
02137 
02138 static int
02139 rfc2822_cb(VALUE m, VALUE hash)
02140 {
02141     VALUE s[SNUM + 1], y;
02142 
02143     {
02144         int i;
02145         s[0] = Qnil;
02146         for (i = 1; i <= SNUM; i++)
02147             s[i] = rb_reg_nth_match(i, m);
02148     }
02149 
02150     set_hash("wday", INT2FIX(day_num(s[1])));
02151     set_hash("mday", str2num(s[2]));
02152     set_hash("mon", INT2FIX(mon_num(s[3])));
02153     y = str2num(s[4]);
02154     if (RSTRING_LEN(s[4]) < 4)
02155         y = comp_year50(y);
02156     set_hash("year", y);
02157     set_hash("hour", str2num(s[5]));
02158     set_hash("min", str2num(s[6]));
02159     if (!NIL_P(s[7]))
02160         set_hash("sec", str2num(s[7]));
02161     set_hash("zone", s[8]);
02162     set_hash("offset", date_zone_to_diff(s[8]));
02163 
02164     return 1;
02165 }
02166 
02167 static int
02168 rfc2822(VALUE str, VALUE hash)
02169 {
02170     static const char pat_source[] =
02171         "\\A\\s*(?:(" ABBR_DAYS ")\\s*,\\s+)?"
02172         "(\\d{1,2})\\s+"
02173         "(" ABBR_MONTHS ")\\s+"
02174         "(-?\\d{2,})\\s+"
02175         "(\\d{2}):(\\d{2})(?::(\\d{2}))?\\s*"
02176         "([-+]\\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\\s*\\z";
02177     static VALUE pat = Qnil;
02178 
02179     REGCOMP_I(pat);
02180     MATCH(str, pat, rfc2822_cb);
02181 }
02182 
02183 VALUE
02184 date__rfc2822(VALUE str)
02185 {
02186     VALUE backref, hash;
02187 
02188     backref = rb_backref_get();
02189     rb_match_busy(backref);
02190 
02191     hash = rb_hash_new();
02192     rfc2822(str, hash);
02193     rb_backref_set(backref);
02194     return hash;
02195 }
02196 
02197 #undef SNUM
02198 #define SNUM 8
02199 
02200 static int
02201 httpdate_type1_cb(VALUE m, VALUE hash)
02202 {
02203     VALUE s[SNUM + 1];
02204 
02205     {
02206         int i;
02207         s[0] = Qnil;
02208         for (i = 1; i <= SNUM; i++)
02209             s[i] = rb_reg_nth_match(i, m);
02210     }
02211 
02212     set_hash("wday", INT2FIX(day_num(s[1])));
02213     set_hash("mday", str2num(s[2]));
02214     set_hash("mon", INT2FIX(mon_num(s[3])));
02215     set_hash("year", str2num(s[4]));
02216     set_hash("hour", str2num(s[5]));
02217     set_hash("min", str2num(s[6]));
02218     set_hash("sec", str2num(s[7]));
02219     set_hash("zone", s[8]);
02220     set_hash("offset", INT2FIX(0));
02221 
02222     return 1;
02223 }
02224 
02225 static int
02226 httpdate_type1(VALUE str, VALUE hash)
02227 {
02228     static const char pat_source[] =
02229         "\\A\\s*(" ABBR_DAYS ")\\s*,\\s+"
02230         "(\\d{2})\\s+"
02231         "(" ABBR_MONTHS ")\\s+"
02232         "(-?\\d{4})\\s+"
02233         "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
02234         "(gmt)\\s*\\z";
02235     static VALUE pat = Qnil;
02236 
02237     REGCOMP_I(pat);
02238     MATCH(str, pat, httpdate_type1_cb);
02239 }
02240 
02241 #undef SNUM
02242 #define SNUM 8
02243 
02244 static int
02245 httpdate_type2_cb(VALUE m, VALUE hash)
02246 {
02247     VALUE s[SNUM + 1], y;
02248 
02249     {
02250         int i;
02251         s[0] = Qnil;
02252         for (i = 1; i <= SNUM; i++)
02253             s[i] = rb_reg_nth_match(i, m);
02254     }
02255 
02256     set_hash("wday", INT2FIX(day_num(s[1])));
02257     set_hash("mday", str2num(s[2]));
02258     set_hash("mon", INT2FIX(mon_num(s[3])));
02259     y = str2num(s[4]);
02260     if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99)))
02261         y = comp_year69(y);
02262     set_hash("year", y);
02263     set_hash("hour", str2num(s[5]));
02264     set_hash("min", str2num(s[6]));
02265     set_hash("sec", str2num(s[7]));
02266     set_hash("zone", s[8]);
02267     set_hash("offset", INT2FIX(0));
02268 
02269     return 1;
02270 }
02271 
02272 static int
02273 httpdate_type2(VALUE str, VALUE hash)
02274 {
02275     static const char pat_source[] =
02276         "\\A\\s*(" DAYS ")\\s*,\\s+"
02277         "(\\d{2})\\s*-\\s*"
02278         "(" ABBR_MONTHS ")\\s*-\\s*"
02279         "(\\d{2})\\s+"
02280         "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
02281         "(gmt)\\s*\\z";
02282     static VALUE pat = Qnil;
02283 
02284     REGCOMP_I(pat);
02285     MATCH(str, pat, httpdate_type2_cb);
02286 }
02287 
02288 #undef SNUM
02289 #define SNUM 7
02290 
02291 static int
02292 httpdate_type3_cb(VALUE m, VALUE hash)
02293 {
02294     VALUE s[SNUM + 1];
02295 
02296     {
02297         int i;
02298         s[0] = Qnil;
02299         for (i = 1; i <= SNUM; i++)
02300             s[i] = rb_reg_nth_match(i, m);
02301     }
02302 
02303     set_hash("wday", INT2FIX(day_num(s[1])));
02304     set_hash("mon", INT2FIX(mon_num(s[2])));
02305     set_hash("mday", str2num(s[3]));
02306     set_hash("hour", str2num(s[4]));
02307     set_hash("min", str2num(s[5]));
02308     set_hash("sec", str2num(s[6]));
02309     set_hash("year", str2num(s[7]));
02310 
02311     return 1;
02312 }
02313 
02314 static int
02315 httpdate_type3(VALUE str, VALUE hash)
02316 {
02317     static const char pat_source[] =
02318         "\\A\\s*(" ABBR_DAYS ")\\s+"
02319         "(" ABBR_MONTHS ")\\s+"
02320         "(\\d{1,2})\\s+"
02321         "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
02322         "(\\d{4})\\s*\\z";
02323     static VALUE pat = Qnil;
02324 
02325     REGCOMP_I(pat);
02326     MATCH(str, pat, httpdate_type3_cb);
02327 }
02328 
02329 VALUE
02330 date__httpdate(VALUE str)
02331 {
02332     VALUE backref, hash;
02333 
02334     backref = rb_backref_get();
02335     rb_match_busy(backref);
02336 
02337     hash = rb_hash_new();
02338 
02339     if (httpdate_type1(str, hash))
02340         goto ok;
02341     if (httpdate_type2(str, hash))
02342         goto ok;
02343     if (httpdate_type3(str, hash))
02344         goto ok;
02345 
02346   ok:
02347     rb_backref_set(backref);
02348 
02349     return hash;
02350 }
02351 
02352 #undef SNUM
02353 #define SNUM 9
02354 
02355 static int
02356 jisx0301_cb(VALUE m, VALUE hash)
02357 {
02358     VALUE s[SNUM + 1];
02359     int ep;
02360 
02361     {
02362         int i;
02363         s[0] = Qnil;
02364         for (i = 1; i <= SNUM; i++)
02365             s[i] = rb_reg_nth_match(i, m);
02366     }
02367 
02368     ep = gengo(NIL_P(s[1]) ? 'h' : *RSTRING_PTR(s[1]));
02369     set_hash("year", f_add(str2num(s[2]), INT2FIX(ep)));
02370     set_hash("mon", str2num(s[3]));
02371     set_hash("mday", str2num(s[4]));
02372     if (!NIL_P(s[5])) {
02373         set_hash("hour", str2num(s[5]));
02374         if (!NIL_P(s[6]))
02375             set_hash("min", str2num(s[6]));
02376         if (!NIL_P(s[7]))
02377             set_hash("sec", str2num(s[7]));
02378     }
02379     if (!NIL_P(s[8]))
02380         set_hash("sec_fraction", sec_fraction(s[8]));
02381     if (!NIL_P(s[9])) {
02382         set_hash("zone", s[9]);
02383         set_hash("offset", date_zone_to_diff(s[9]));
02384     }
02385 
02386     return 1;
02387 }
02388 
02389 static int
02390 jisx0301(VALUE str, VALUE hash)
02391 {
02392     static const char pat_source[] =
02393         "\\A\\s*([mtsh])?(\\d{2})\\.(\\d{2})\\.(\\d{2})"
02394         "(?:t"
02395         "(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d*))?)?"
02396         "(z|[-+]\\d{2}(?::?\\d{2})?)?)?)?\\s*\\z";
02397     static VALUE pat = Qnil;
02398 
02399     REGCOMP_I(pat);
02400     MATCH(str, pat, jisx0301_cb);
02401 }
02402 
02403 VALUE
02404 date__jisx0301(VALUE str)
02405 {
02406     VALUE backref, hash;
02407 
02408     backref = rb_backref_get();
02409     rb_match_busy(backref);
02410 
02411     hash = rb_hash_new();
02412     if (jisx0301(str, hash))
02413         goto ok;
02414     hash = date__iso8601(str);
02415 
02416   ok:
02417     rb_backref_set(backref);
02418     return hash;
02419 }
02420 
02421 /*
02422 Local variables:
02423 c-file-style: "ruby"
02424 End:
02425 */
02426