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 TIGHT_PARSER */
00011 
00012 #define sizeof_array(o) (sizeof o / sizeof o[0])
00013 
00014 #define f_negate(x) rb_funcall(x, rb_intern("-@"), 0)
#define f_add(x,y) rb_funcall(x, '+', 1, y)
#define f_sub(x,y) rb_funcall(x, '-', 1, y)
#define f_mul(x,y) rb_funcall(x, '*', 1, y)
#define f_div(x,y) rb_funcall(x, '/', 1, y)
#define f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y)
00015 #define f_mod(x,y) rb_funcall(x, '%', 1, y)
00016 #define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y)
00017 
00018 #define f_lt_p(x,y) rb_funcall(x, '<', 1, y)
00019 #define f_gt_p(x,y) rb_funcall(x, '>', 1, y)
00020 #define f_le_p(x,y) rb_funcall(x, rb_intern("<="), 1, y)
00021 #define f_ge_p(x,y) rb_funcall(x, rb_intern(">="), 1, y)
00022 
00023 #define f_to_s(x) rb_funcall(x, rb_intern("to_s"), 0)
00024 
00025 #define f_match(r,s) rb_funcall(r, rb_intern("match"), 1, s)
00026 #define f_aref(o,i) rb_funcall(o, rb_intern("[]"), 1, i)
00027 #define f_aref2(o,i,j) rb_funcall(o, rb_intern("[]"), 2, i, j)
00028 #define f_begin(o,i) rb_funcall(o, rb_intern("begin"), 1, i)
00029 #define f_end(o,i) rb_funcall(o, rb_intern("end"), 1, i)
00030 #define f_aset(o,i,v) rb_funcall(o, rb_intern("[]="), 2, i, v)
00031 #define f_aset2(o,i,j,v) rb_funcall(o, rb_intern("[]="), 3, i, j, v)
00032 #define f_sub_bang(s,r,x) rb_funcall(s, rb_intern("sub!"), 2, r, x)
00033 #define f_gsub_bang(s,r,x) rb_funcall(s, rb_intern("gsub!"), 2, r, x)
00034 
00035 #define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v)
00036 #define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k)))
00037 #define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k)))
00038 
00039 #define cstr2num(s) rb_cstr_to_inum(s, 10, 0)
00040 #define str2num(s) rb_str_to_inum(s, 10, 0)
00041 
00042 static const char *abbr_days[] = {
00043     "sun", "mon", "tue", "wed",
00044     "thu", "fri", "sat"
00045 };
00046 
00047 static const char *abbr_months[] = {
00048     "jan", "feb", "mar", "apr", "may", "jun",
00049     "jul", "aug", "sep", "oct", "nov", "dec"
00050 };
00051 
00052 #define issign(c) ((c) == '-' || (c) == '+')
00053 #define asp_string() rb_str_new(" ", 1)
00054 #ifdef TIGHT_PARSER
00055 #define asuba_string() rb_str_new("\001", 1)
00056 #define asubb_string() rb_str_new("\002", 1)
00057 #define asubw_string() rb_str_new("\027", 1)
00058 #define asubt_string() rb_str_new("\024", 1)
00059 #endif
00060 
00061 #define DECDIGIT "0123456789"
00062 
00063 static void
00064 s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc)
00065 {
00066     VALUE c = Qnil;
00067 
00068     if (TYPE(m) != T_STRING)
00069         m = f_to_s(m);
00070 
00071     if (!NIL_P(y) && !NIL_P(m) && NIL_P(d)) {
00072         VALUE oy = y;
00073         VALUE om = m;
00074         VALUE od = d;
00075 
00076         y = od;
00077         m = oy;
00078         d = om;
00079     }
00080 
00081     if (NIL_P(y)) {
00082         if (!NIL_P(d) && RSTRING_LEN(d) > 2) {
00083             y = d;
00084             d = Qnil;
00085         }
00086         if (!NIL_P(d) && *RSTRING_PTR(d) == '\'') {
00087             y = d;
00088             d = Qnil;
00089         }
00090     }
00091 
00092     if (!NIL_P(y)) {
00093         const char *s, *bp, *ep;
00094         size_t l;
00095 
00096         s = RSTRING_PTR(y);
00097         while (!issign((unsigned char)*s) && !isdigit((unsigned char)*s))
00098             s++;
00099         bp = s;
00100         if (issign((unsigned char)*s))
00101             s++;
00102         l = strspn(s, DECDIGIT);
00103         ep = s + l;
00104         if (*ep) {
00105             y = d;
00106             d = rb_str_new(bp, ep - bp);
00107         }
00108     }
00109 
00110     if (!NIL_P(m)) {
00111         const char *s;
00112 
00113         s = RSTRING_PTR(m);
00114         if (*s == '\'' || RSTRING_LEN(m) > 2) {
00115             /* us -> be */
00116             VALUE oy = y;
00117             VALUE om = m;
00118             VALUE od = d;
00119 
00120             y = om;
00121             m = od;
00122             d = oy;
00123         }
00124     }
00125 
00126     if (!NIL_P(d)) {
00127         const char *s;
00128 
00129         s = RSTRING_PTR(d);
00130         if (*s == '\'' || RSTRING_LEN(d) > 2) {
00131             VALUE oy = y;
00132             VALUE od = d;
00133 
00134             y = od;
00135             d = oy;
00136         }
00137     }
00138 
00139     if (!NIL_P(y)) {
00140         const char *s, *bp, *ep;
00141         int sign = 0;
00142         size_t l;
00143         VALUE iy;
00144 
00145         s = RSTRING_PTR(y);
00146         while (!issign((unsigned char)*s) && !isdigit((unsigned char)*s))
00147             s++;
00148         bp = s;
00149         if (issign(*s)) {
00150             s++;
00151             sign = 1;
00152         }
00153         if (sign)
00154             c = Qfalse;
00155         l = strspn(s, DECDIGIT);
00156         ep = s + l;
00157         if (l > 2)
00158             c = Qfalse;
00159         {
00160             char *buf;
00161 
00162             buf = ALLOCA_N(char, ep - bp + 1);
00163             memcpy(buf, bp, ep - bp);
00164             buf[ep - bp] = '\0';
00165             iy = cstr2num(buf);
00166         }
00167         set_hash("year", iy);
00168     }
00169 
00170     if (bc)
00171         set_hash("_bc", Qtrue);
00172 
00173     if (!NIL_P(m)) {
00174         const char *s, *bp, *ep;
00175         size_t l;
00176         VALUE im;
00177 
00178         s = RSTRING_PTR(m);
00179         while (!isdigit((unsigned char)*s))
00180             s++;
00181         bp = s;
00182         l = strspn(s, DECDIGIT);
00183         ep = s + l;
00184         {
00185             char *buf;
00186 
00187             buf = ALLOCA_N(char, ep - bp + 1);
00188             memcpy(buf, bp, ep - bp);
00189             buf[ep - bp] = '\0';
00190             im = cstr2num(buf);
00191         }
00192         set_hash("mon", im);
00193     }
00194 
00195     if (!NIL_P(d)) {
00196         const char *s, *bp, *ep;
00197         size_t l;
00198         VALUE id;
00199 
00200         s = RSTRING_PTR(d);
00201         while (!isdigit((unsigned char)*s))
00202             s++;
00203         bp = s;
00204         l = strspn(s, DECDIGIT);
00205         ep = s + l;
00206         {
00207             char *buf;
00208 
00209             buf = ALLOCA_N(char, ep - bp + 1);
00210             memcpy(buf, bp, ep - bp);
00211             buf[ep - bp] = '\0';
00212             id = cstr2num(buf);
00213         }
00214         set_hash("mday", id);
00215     }
00216 
00217     if (!NIL_P(c))
00218         set_hash("_comp", c);
00219 }
00220 
00221 #define DAYS "sunday|monday|tuesday|wednesday|thursday|friday|saturday"
00222 #define MONTHS "january|february|march|april|may|june|july|august|september|october|november|december"
00223 #define ABBR_DAYS "sun|mon|tue|wed|thu|fri|sat"
00224 #define ABBR_MONTHS "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec"
00225 
00226 #ifdef TIGHT_PARSER
00227 #define VALID_DAYS "(?:" DAYS ")" "|(?:tues|wednes|thurs|thur|" ABBR_DAYS ")\\.?"
00228 #define VALID_MONTHS "(?:" MONTHS ")" "|(?:sept|" ABBR_MONTHS ")\\.?"
00229 #define DOTLESS_VALID_MONTHS "(?:" MONTHS ")" "|(?:sept|" ABBR_MONTHS ")"
00230 #define BOS "\\A\\s*"
00231 #define FPA "\\001"
00232 #define FPB "\\002"
00233 #define FPW "\\027"
00234 #define FPT "\\024"
00235 #define FPW_COM "\\s*(?:" FPW "\\s*,?)?\\s*"
00236 #define FPT_COM "\\s*(?:" FPT "\\s*,?)?\\s*"
00237 #define COM_FPW "\\s*(?:,?\\s*" FPW ")?\\s*"
00238 #define COM_FPT "\\s*(?:,?\\s*(?:@|\\b[aA][tT]\\b)?\\s*" FPT ")?\\s*"
00239 #define TEE_FPT "\\s*(?:[tT]?" FPT ")?"
00240 #define EOS "\\s*\\z"
00241 #endif
00242 
00243 static VALUE
00244 regcomp(const char *source, long len, int opt)
00245 {
00246     VALUE pat;
00247 
00248     pat = rb_reg_new(source, len, opt);
00249     rb_gc_register_mark_object(pat);
00250     return pat;
00251 }
00252 
00253 #define REGCOMP(pat,opt) \
00254 { \
00255     if (NIL_P(pat)) \
00256         pat = regcomp(pat##_source, sizeof pat##_source - 1, opt); \
00257 }
00258 
00259 #define REGCOMP_0(pat) REGCOMP(pat, 0)
00260 #define REGCOMP_I(pat) REGCOMP(pat, ONIG_OPTION_IGNORECASE)
00261 
00262 #define MATCH(s,p,c) \
00263 { \
00264     return match(s, p, hash, c); \
00265 }
00266 
00267 static int
00268 match(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE))
00269 {
00270     VALUE m;
00271 
00272     m = f_match(pat, str);
00273 
00274     if (NIL_P(m))
00275         return 0;
00276 
00277     (*cb)(m, hash);
00278 
00279     return 1;
00280 }
00281 
00282 static int
00283 subx(VALUE str, VALUE rep, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE))
00284 {
00285     VALUE m;
00286 
00287     m = f_match(pat, str);
00288 
00289     if (NIL_P(m))
00290         return 0;
00291 
00292     {
00293         VALUE be, en;
00294 
00295         be = f_begin(m, INT2FIX(0));
00296         en = f_end(m, INT2FIX(0));
00297         f_aset2(str, be, LONG2NUM(NUM2LONG(en) - NUM2LONG(be)), rep);
00298         (*cb)(m, hash);
00299     }
00300 
00301     return 1;
00302 }
00303 
00304 #define SUBS(s,p,c) \
00305 { \
00306     return subx(s, asp_string(), p, hash, c); \
00307 }
00308 
00309 #ifdef TIGHT_PARSER
00310 #define SUBA(s,p,c) \
00311 { \
00312     return subx(s, asuba_string(), p, hash, c); \
00313 }
00314 
00315 #define SUBB(s,p,c) \
00316 { \
00317     return subx(s, asubb_string(), p, hash, c); \
00318 }
00319 
00320 #define SUBW(s,p,c) \
00321 { \
00322     return subx(s, asubw_string(), p, hash, c); \
00323 }
00324 
00325 #define SUBT(s,p,c) \
00326 { \
00327     return subx(s, asubt_string(), p, hash, c); \
00328 }
00329 #endif
00330 
00331 struct zone {
00332     const char *name;
00333     int offset;
00334 };
00335 
00336 static struct zone zones_source[] = {
00337     {"ut",   0*3600}, {"gmt",  0*3600}, {"est", -5*3600}, {"edt", -4*3600},
00338     {"cst", -6*3600}, {"cdt", -5*3600}, {"mst", -7*3600}, {"mdt", -6*3600},
00339     {"pst", -8*3600}, {"pdt", -7*3600},
00340     {"a",    1*3600}, {"b",    2*3600}, {"c",    3*3600}, {"d",    4*3600},
00341     {"e",    5*3600}, {"f",    6*3600}, {"g",    7*3600}, {"h",    8*3600},
00342     {"i",    9*3600}, {"k",   10*3600}, {"l",   11*3600}, {"m",   12*3600},
00343     {"n",   -1*3600}, {"o",   -2*3600}, {"p",   -3*3600}, {"q",   -4*3600},
00344     {"r",   -5*3600}, {"s",   -6*3600}, {"t",   -7*3600}, {"u",   -8*3600},
00345     {"v",   -9*3600}, {"w",  -10*3600}, {"x",  -11*3600}, {"y",  -12*3600},
00346     {"z",    0*3600},
00347 
00348     {"utc",  0*3600}, {"wet",  0*3600},
00349     {"at",  -2*3600}, {"brst",-2*3600}, {"ndt", -(2*3600+1800)},
00350     {"art", -3*3600}, {"adt", -3*3600}, {"brt", -3*3600}, {"clst",-3*3600},
00351     {"nst", -(3*3600+1800)},
00352     {"ast", -4*3600}, {"clt", -4*3600},
00353     {"akdt",-8*3600}, {"ydt", -8*3600},
00354     {"akst",-9*3600}, {"hadt",-9*3600}, {"hdt", -9*3600}, {"yst", -9*3600},
00355     {"ahst",-10*3600},{"cat",-10*3600}, {"hast",-10*3600},{"hst",-10*3600},
00356     {"nt",  -11*3600},
00357     {"idlw",-12*3600},
00358     {"bst",  1*3600}, {"cet",  1*3600}, {"fwt",  1*3600}, {"met",  1*3600},
00359     {"mewt", 1*3600}, {"mez",  1*3600}, {"swt",  1*3600}, {"wat",  1*3600},
00360     {"west", 1*3600},
00361     {"cest", 2*3600}, {"eet",  2*3600}, {"fst",  2*3600}, {"mest", 2*3600},
00362     {"mesz", 2*3600}, {"sast", 2*3600}, {"sst",  2*3600},
00363     {"bt",   3*3600}, {"eat",  3*3600}, {"eest", 3*3600}, {"msk",  3*3600},
00364     {"msd",  4*3600}, {"zp4",  4*3600},
00365     {"zp5",  5*3600}, {"ist",  (5*3600+1800)},
00366     {"zp6",  6*3600},
00367     {"wast", 7*3600},
00368     {"cct",  8*3600}, {"sgt",  8*3600}, {"wadt", 8*3600},
00369     {"jst",  9*3600}, {"kst",  9*3600},
00370     {"east",10*3600}, {"gst", 10*3600},
00371     {"eadt",11*3600},
00372     {"idle",12*3600}, {"nzst",12*3600}, {"nzt", 12*3600},
00373     {"nzdt",13*3600},
00374 
00375     {"afghanistan",             16200}, {"alaskan",                -32400},
00376     {"arab",                    10800}, {"arabian",                 14400},
00377     {"arabic",                  10800}, {"atlantic",               -14400},
00378     {"aus central",             34200}, {"aus eastern",             36000},
00379     {"azores",                  -3600}, {"canada central",         -21600},
00380     {"cape verde",              -3600}, {"caucasus",                14400},
00381     {"cen. australia",          34200}, {"central america",        -21600},
00382     {"central asia",            21600}, {"central europe",           3600},
00383     {"central european",         3600}, {"central pacific",         39600},
00384     {"central",                -21600}, {"china",                   28800},
00385     {"dateline",               -43200}, {"e. africa",               10800},
00386     {"e. australia",            36000}, {"e. europe",                7200},
00387     {"e. south america",       -10800}, {"eastern",                -18000},
00388     {"egypt",                    7200}, {"ekaterinburg",            18000},
00389     {"fiji",                    43200}, {"fle",                      7200},
00390     {"greenland",              -10800}, {"greenwich",                   0},
00391     {"gtb",                      7200}, {"hawaiian",               -36000},
00392     {"india",                   19800}, {"iran",                    12600},
00393     {"jerusalem",                7200}, {"korea",                   32400},
00394     {"mexico",                 -21600}, {"mid-atlantic",            -7200},
00395     {"mountain",               -25200}, {"myanmar",                 23400},
00396     {"n. central asia",         21600}, {"nepal",                   20700},
00397     {"new zealand",             43200}, {"newfoundland",           -12600},
00398     {"north asia east",         28800}, {"north asia",              25200},
00399     {"pacific sa",             -14400}, {"pacific",                -28800},
00400     {"romance",                  3600}, {"russian",                 10800},
00401     {"sa eastern",             -10800}, {"sa pacific",             -18000},
00402     {"sa western",             -14400}, {"samoa",                  -39600},
00403     {"se asia",                 25200}, {"malay peninsula",         28800},
00404     {"south africa",             7200}, {"sri lanka",               21600},
00405     {"taipei",                  28800}, {"tasmania",                36000},
00406     {"tokyo",                   32400}, {"tonga",                   46800},
00407     {"us eastern",             -18000}, {"us mountain",            -25200},
00408     {"vladivostok",             36000}, {"w. australia",            28800},
00409     {"w. central africa",        3600}, {"w. europe",                3600},
00410     {"west asia",               18000}, {"west pacific",            36000},
00411     {"yakutsk",                 32400}
00412 };
00413 
00414 VALUE
00415 date_zone_to_diff(VALUE str)
00416 {
00417     VALUE offset = Qnil;
00418 
00419     long l, i;
00420     char *s, *dest, *d;
00421     int sp = 1;
00422 
00423     l = RSTRING_LEN(str);
00424     s = RSTRING_PTR(str);
00425 
00426     dest = d = ALLOCA_N(char, l + 1);
00427 
00428     for (i = 0; i < l; i++) {
00429         if (isspace((unsigned char)s[i]) || s[i] == '\0') {
00430             if (!sp)
00431                 *d++ = ' ';
00432             sp = 1;
00433         }
00434         else {
00435             if (isalpha((unsigned char)s[i]))
00436                 *d++ = tolower((unsigned char)s[i]);
00437             else
00438                 *d++ = s[i];
00439             sp = 0;
00440         }
00441     }
00442     if (d > dest) {
00443         if (*(d - 1) == ' ')
00444             --d;
00445         *d = '\0';
00446     }
00447     str = rb_str_new2(dest);
00448     {
00449 #define STD " standard time"
00450 #define DST " daylight time"
00451         char *ss, *ds;
00452         long sl, dl;
00453         int dst = 0;
00454 
00455         sl = RSTRING_LEN(str) - (sizeof STD - 1);
00456         ss = RSTRING_PTR(str) + sl;
00457         dl = RSTRING_LEN(str) - (sizeof DST - 1);
00458         ds = RSTRING_PTR(str) + dl;
00459 
00460         if (sl >= 0 && strcmp(ss, STD) == 0) {
00461             str = rb_str_new(RSTRING_PTR(str), sl);
00462         }
00463         else if (dl >= 0 && strcmp(ds, DST) == 0) {
00464             str = rb_str_new(RSTRING_PTR(str), dl);
00465             dst = 1;
00466         }
00467 #undef STD
00468 #undef DST
00469         else {
00470 #define DST " dst"
00471             char *ds;
00472             long dl;
00473 
00474             dl = RSTRING_LEN(str) - (sizeof DST - 1);
00475             ds = RSTRING_PTR(str) + dl;
00476 
00477             if (dl >= 0 && strcmp(ds, DST) == 0) {
00478                 str = rb_str_new(RSTRING_PTR(str), dl);
00479                 dst = 1;
00480             }
00481 #undef DST
00482         }
00483         {
00484             static VALUE zones = Qnil;
00485 
00486             if (NIL_P(zones)) {
00487                 int i;
00488 
00489                 zones = rb_hash_new();
00490                 rb_gc_register_mark_object(zones);
00491                 for (i = 0; i < (int)sizeof_array(zones_source); i++) {
00492                     VALUE name = rb_str_new2(zones_source[i].name);
00493                     VALUE offset = INT2FIX(zones_source[i].offset);
00494                     rb_hash_aset(zones, name, offset);
00495                 }
00496             }
00497 
00498             offset = f_aref(zones, str);
00499             if (!NIL_P(offset)) {
00500                 if (dst)
00501                     offset = f_add(offset, INT2FIX(3600));
00502                 goto ok;
00503             }
00504         }
00505         {
00506             char *s, *p;
00507             VALUE sign;
00508             VALUE hour = Qnil, min = Qnil, sec = Qnil;
00509             VALUE str_orig;
00510 
00511             s = RSTRING_PTR(str);
00512             str_orig = str;
00513 
00514             if (strncmp(s, "gmt", 3) == 0 ||
00515                 strncmp(s, "utc", 3) == 0)
00516                 s += 3;
00517             if (issign(*s)) {
00518                 sign = rb_str_new(s, 1);
00519                 s++;
00520 
00521                 str = rb_str_new2(s);
00522 
00523                 if (p = strchr(s, ':')) {
00524                     hour = rb_str_new(s, p - s);
00525                     s = ++p;
00526                     if (p = strchr(s, ':')) {
00527                         min = rb_str_new(s, p - s);
00528                         s = ++p;
00529                         if (p = strchr(s, ':')) {
00530                             sec = rb_str_new(s, p - s);
00531                         }
00532                         else
00533                             sec = rb_str_new2(s);
00534                     }
00535                     else
00536                         min = rb_str_new2(s);
00537                     RB_GC_GUARD(str_orig);
00538                     goto num;
00539                 }
00540                 if (strpbrk(RSTRING_PTR(str), ",.")) {
00541                     char *a, *b;
00542 
00543                     a = ALLOCA_N(char, RSTRING_LEN(str) + 1);
00544                     strcpy(a, RSTRING_PTR(str));
00545                     b = strpbrk(a, ",.");
00546                     *b = '\0';
00547                     b++;
00548 
00549                     hour = cstr2num(a);
00550                     min = f_mul(rb_rational_new2
00551                                 (cstr2num(b),
00552                                  f_expt(INT2FIX(10),
00553                                         LONG2NUM((long)strlen(b)))),
00554                                 INT2FIX(60));
00555                     goto num;
00556                 }
00557                 {
00558                     const char *cs = RSTRING_PTR(str);
00559                     long cl = RSTRING_LEN(str);
00560 
00561                     if (cl % 2) {
00562                         if (cl >= 1)
00563                             hour = rb_str_new(&cs[0], 1);
00564                         if (cl >= 3)
00565                             min  = rb_str_new(&cs[1], 2);
00566                         if (cl >= 5)
00567                             sec  = rb_str_new(&cs[3], 2);
00568                     }
00569                     else {
00570                         if (cl >= 2)
00571                             hour = rb_str_new(&cs[0], 2);
00572                         if (cl >= 4)
00573                             min  = rb_str_new(&cs[2], 2);
00574                         if (cl >= 6)
00575                             sec  = rb_str_new(&cs[4], 2);
00576                     }
00577                     goto num;
00578                 }
00579               num:
00580                 if (NIL_P(hour))
00581                     offset = INT2FIX(0);
00582                 else {
00583                     if (TYPE(hour) == T_STRING)
00584                         hour = str2num(hour);
00585                     offset = f_mul(hour, INT2FIX(3600));
00586                 }
00587                 if (!NIL_P(min)) {
00588                     if (TYPE(min) == T_STRING)
00589                         min = str2num(min);
00590                     offset = f_add(offset, f_mul(min, INT2FIX(60)));
00591                 }
00592                 if (!NIL_P(sec))
00593                     offset = f_add(offset, str2num(sec));
00594                 if (!NIL_P(sign) &&
00595                     RSTRING_LEN(sign) == 1 &&
00596                     *RSTRING_PTR(sign) == '-')
00597                     offset = f_negate(offset);
00598             }
00599         }
00600     }
00601     RB_GC_GUARD(str);
00602   ok:
00603     return offset;
00604 }
00605 
00606 static int
00607 day_num(VALUE s)
00608 {
00609     int i;
00610 
00611     for (i = 0; i < (int)sizeof_array(abbr_days); i++)
00612         if (strncasecmp(abbr_days[i], RSTRING_PTR(s), 3) == 0)
00613             break;
00614     return i;
00615 }
00616 
00617 static int
00618 mon_num(VALUE s)
00619 {
00620     int i;
00621 
00622     for (i = 0; i < (int)sizeof_array(abbr_months); i++)
00623         if (strncasecmp(abbr_months[i], RSTRING_PTR(s), 3) == 0)
00624             break;
00625     return i + 1;
00626 }
00627 
00628 static int
00629 parse_day_cb(VALUE m, VALUE hash)
00630 {
00631     VALUE s;
00632 
00633     s = rb_reg_nth_match(1, m);
00634     set_hash("wday", INT2FIX(day_num(s)));
00635     return 1;
00636 }
00637 
00638 static int
00639 parse_day(VALUE str, VALUE hash)
00640 {
00641     static const char pat_source[] =
00642 #ifndef TIGHT_PARSER
00643         "\\b(" ABBR_DAYS ")[^-/\\d\\s]*"
00644 #else
00645         "(" VALID_DAYS ")"
00646 #endif
00647         ;
00648     static VALUE pat = Qnil;
00649 
00650     REGCOMP_I(pat);
00651 #ifndef TIGHT_PARSER
00652     SUBS(str, pat, parse_day_cb);
00653 #else
00654     SUBW(str, pat, parse_day_cb);
00655 #endif
00656 }
00657 
00658 static int
00659 parse_time2_cb(VALUE m, VALUE hash)
00660 {
00661     VALUE h, min, s, f, p;
00662 
00663     h = rb_reg_nth_match(1, m);
00664     h = str2num(h);
00665 
00666     min = rb_reg_nth_match(2, m);
00667     if (!NIL_P(min))
00668         min = str2num(min);
00669 
00670     s = rb_reg_nth_match(3, m);
00671     if (!NIL_P(s))
00672         s = str2num(s);
00673 
00674     f = rb_reg_nth_match(4, m);
00675 
00676     if (!NIL_P(f))
00677         f = rb_rational_new2(str2num(f),
00678                              f_expt(INT2FIX(10), LONG2NUM(RSTRING_LEN(f))));
00679 
00680     p = rb_reg_nth_match(5, m);
00681 
00682     if (!NIL_P(p)) {
00683         int ih = NUM2INT(h);
00684         ih %= 12;
00685         if (*RSTRING_PTR(p) == 'P' || *RSTRING_PTR(p) == 'p')
00686             ih += 12;
00687         h = INT2FIX(ih);
00688     }
00689 
00690     set_hash("hour", h);
00691     if (!NIL_P(min))
00692         set_hash("min", min);
00693     if (!NIL_P(s))
00694         set_hash("sec", s);
00695     if (!NIL_P(f))
00696         set_hash("sec_fraction", f);
00697 
00698     return 1;
00699 }
00700 
00701 static int
00702 parse_time_cb(VALUE m, VALUE hash)
00703 {
00704     static const char pat_source[] =
00705             "\\A(\\d+)h?"
00706               "(?:\\s*:?\\s*(\\d+)m?"
00707                 "(?:"
00708                   "\\s*:?\\s*(\\d+)(?:[,.](\\d+))?s?"
00709                 ")?"
00710               ")?"
00711             "(?:\\s*([ap])(?:m\\b|\\.m\\.))?";
00712     static VALUE pat = Qnil;
00713     VALUE s1, s2;
00714 
00715     s1 = rb_reg_nth_match(1, m);
00716     s2 = rb_reg_nth_match(2, m);
00717 
00718     if (!NIL_P(s2))
00719         set_hash("zone", s2);
00720 
00721     REGCOMP_I(pat);
00722 
00723     {
00724         VALUE m = f_match(pat, s1);
00725 
00726         if (NIL_P(m))
00727             return 0;
00728         parse_time2_cb(m, hash);
00729     }
00730 
00731     return 1;
00732 }
00733 
00734 static int
00735 parse_time(VALUE str, VALUE hash)
00736 {
00737     static const char pat_source[] =
00738                 "("
00739                    "(?:"
00740                      "\\d+\\s*:\\s*\\d+"
00741                      "(?:"
00742 #ifndef TIGHT_PARSER
00743                        "\\s*:\\s*\\d+(?:[,.]\\d*)?"
00744 #else
00745                        "\\s*:\\s*\\d+(?:[,.]\\d+)?"
00746 #endif
00747                      ")?"
00748                    "|"
00749                      "\\d+\\s*h(?:\\s*\\d+m?(?:\\s*\\d+s?)?)?"
00750                    ")"
00751                    "(?:"
00752                      "\\s*"
00753                      "[ap](?:m\\b|\\.m\\.)"
00754                    ")?"
00755                  "|"
00756                    "\\d+\\s*[ap](?:m\\b|\\.m\\.)"
00757                  ")"
00758                  "(?:"
00759                    "\\s*"
00760                    "("
00761                      "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?"
00762                    "|"
00763                      "(?-i:[[:alpha:].\\s]+)(?:standard|daylight)\\stime\\b"
00764                    "|"
00765                      "(?-i:[[:alpha:]]+)(?:\\sdst)?\\b"
00766                    ")"
00767                 ")?";
00768     static VALUE pat = Qnil;
00769 
00770     REGCOMP_I(pat);
00771 #ifndef TIGHT_PARSER
00772     SUBS(str, pat, parse_time_cb);
00773 #else
00774     SUBT(str, pat, parse_time_cb);
00775 #endif
00776 }
00777 
00778 #ifdef TIGHT_PARSER
00779 static int
00780 parse_era1_cb(VALUE m, VALUE hash)
00781 {
00782     return 1;
00783 }
00784 
00785 static int
00786 parse_era1(VALUE str, VALUE hash)
00787 {
00788     static const char pat_source[] =
00789         "(a(?:d|\\.d\\.))";
00790     static VALUE pat = Qnil;
00791 
00792     REGCOMP_I(pat);
00793     SUBA(str, pat, parse_era1_cb);
00794 }
00795 
00796 static int
00797 parse_era2_cb(VALUE m, VALUE hash)
00798 {
00799     VALUE b;
00800 
00801     b = rb_reg_nth_match(1, m);
00802     if (*RSTRING_PTR(b) == 'B' ||
00803         *RSTRING_PTR(b) == 'b')
00804         set_hash("_bc", Qtrue);
00805     return 1;
00806 }
00807 
00808 static int
00809 parse_era2(VALUE str, VALUE hash)
00810 {
00811     static const char pat_source[] =
00812         "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|b(?:c|\\.c\\.))";
00813     static VALUE pat = Qnil;
00814 
00815     REGCOMP_I(pat);
00816     SUBB(str, pat, parse_era2_cb);
00817 }
00818 
00819 static int
00820 parse_era(VALUE str, VALUE hash)
00821 {
00822     if (parse_era1(str, hash)) /* pre */
00823         goto ok;
00824     if (parse_era2(str, hash)) /* post */
00825         goto ok;
00826     return 0;
00827   ok:
00828     return 1;
00829 }
00830 #endif
00831 
00832 #ifdef TIGHT_PARSER
00833 static int
00834 check_year_width(VALUE y)
00835 {
00836     char *s;
00837     size_t l;
00838 
00839     s = RSTRING_PTR(y);
00840     l = strcspn(s, DECDIGIT);
00841     s += l;
00842     l = strspn(s, DECDIGIT);
00843     if (l != 2)
00844         return 0;
00845     return 1;
00846 }
00847 
00848 static int
00849 check_apost(VALUE a, VALUE b, VALUE c)
00850 {
00851     int f = 0;
00852 
00853     if (!NIL_P(a) && *RSTRING_PTR(a) == '\'') {
00854         if (!check_year_width(a))
00855             return 0;
00856         f++;
00857     }
00858     if (!NIL_P(b) && *RSTRING_PTR(b) == '\'') {
00859         if (!check_year_width(b))
00860             return 0;
00861         if (!NIL_P(c))
00862             return 0;
00863         f++;
00864     }
00865     if (!NIL_P(c) && *RSTRING_PTR(c) == '\'') {
00866         if (!check_year_width(c))
00867             return 0;
00868         f++;
00869     }
00870     if (f > 1)
00871         return 0;
00872     return 1;
00873 }
00874 #endif
00875 
00876 static int
00877 parse_eu_cb(VALUE m, VALUE hash)
00878 {
00879 #ifndef TIGHT_PARSER
00880     VALUE y, mon, d, b;
00881 
00882     d = rb_reg_nth_match(1, m);
00883     mon = rb_reg_nth_match(2, m);
00884     b = rb_reg_nth_match(3, m);
00885     y = rb_reg_nth_match(4, m);
00886 
00887     mon = INT2FIX(mon_num(mon));
00888 
00889     s3e(hash, y, mon, d, !NIL_P(b) &&
00890         (*RSTRING_PTR(b) == 'B' ||
00891          *RSTRING_PTR(b) == 'b'));
00892 #else
00893     VALUE y, mon, d;
00894 
00895     d = rb_reg_nth_match(1, m);
00896     mon = rb_reg_nth_match(2, m);
00897     y = rb_reg_nth_match(3, m);
00898 
00899     if (!check_apost(d, mon, y))
00900         return 0;
00901 
00902     mon = INT2FIX(mon_num(mon));
00903 
00904     s3e(hash, y, mon, d, 0);
00905 #endif
00906     return 1;
00907 }
00908 
00909 static int
00910 parse_eu(VALUE str, VALUE hash)
00911 {
00912     static const char pat_source[] =
00913 #ifdef TIGHT_PARSER
00914                 BOS
00915                 FPW_COM FPT_COM
00916 #endif
00917 #ifndef TIGHT_PARSER
00918                 "('?\\d+)[^-\\d\\s]*"
00919 #else
00920                 "(\\d+)(?:(?:st|nd|rd|th)\\b)?"
00921 #endif
00922                  "\\s*"
00923 #ifndef TIGHT_PARSER
00924                  "(" ABBR_MONTHS ")[^-\\d\\s']*"
00925 #else
00926                  "(" VALID_MONTHS ")"
00927 #endif
00928                  "(?:"
00929                    "\\s*"
00930 #ifndef TIGHT_PARSER
00931                    "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?"
00932                    "\\s*"
00933                    "('?-?\\d+(?:(?:st|nd|rd|th)\\b)?)"
00934 #else
00935                    "(?:" FPA ")?"
00936                    "\\s*"
00937                    "([-']?\\d+)"
00938                    "\\s*"
00939                    "(?:" FPA "|" FPB ")?"
00940 #endif
00941                 ")?"
00942 #ifdef TIGHT_PARSER
00943                 COM_FPT COM_FPW
00944                 EOS
00945 #endif
00946                 ;
00947     static VALUE pat = Qnil;
00948 
00949     REGCOMP_I(pat);
00950     SUBS(str, pat, parse_eu_cb);
00951 }
00952 
00953 static int
00954 parse_us_cb(VALUE m, VALUE hash)
00955 {
00956 #ifndef TIGHT_PARSER
00957     VALUE y, mon, d, b;
00958 
00959     mon = rb_reg_nth_match(1, m);
00960     d = rb_reg_nth_match(2, m);
00961 
00962     b = rb_reg_nth_match(3, m);
00963     y = rb_reg_nth_match(4, m);
00964 
00965     mon = INT2FIX(mon_num(mon));
00966 
00967     s3e(hash, y, mon, d, !NIL_P(b) &&
00968         (*RSTRING_PTR(b) == 'B' ||
00969          *RSTRING_PTR(b) == 'b'));
00970 #else
00971     VALUE y, mon, d;
00972 
00973     mon = rb_reg_nth_match(1, m);
00974     d = rb_reg_nth_match(2, m);
00975     y = rb_reg_nth_match(3, m);
00976 
00977     if (!check_apost(mon, d, y))
00978         return 0;
00979 
00980     mon = INT2FIX(mon_num(mon));
00981 
00982     s3e(hash, y, mon, d, 0);
00983 #endif
00984     return 1;
00985 }
00986 
00987 static int
00988 parse_us(VALUE str, VALUE hash)
00989 {
00990     static const char pat_source[] =
00991 #ifdef TIGHT_PARSER
00992                 BOS
00993                 FPW_COM FPT_COM
00994 #endif
00995 #ifndef TIGHT_PARSER
00996                 "\\b(" ABBR_MONTHS ")[^-\\d\\s']*"
00997 #else
00998                 "\\b(" VALID_MONTHS ")"
00999 #endif
01000                  "\\s*"
01001 #ifndef TIGHT_PARSER
01002                  "('?\\d+)[^-\\d\\s']*"
01003 #else
01004                  "('?\\d+)(?:(?:st|nd|rd|th)\\b)?"
01005                 COM_FPT
01006 #endif
01007                  "(?:"
01008                    "\\s*,?"
01009                    "\\s*"
01010 #ifndef TIGHT_PARSER
01011                    "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?"
01012                    "\\s*"
01013                    "('?-?\\d+)"
01014 #else
01015                    "(?:" FPA ")?"
01016                    "\\s*"
01017                    "([-']?\\d+)"
01018                    "\\s*"
01019                    "(?:" FPA "|" FPB ")?"
01020 #endif
01021                 ")?"
01022 #ifdef TIGHT_PARSER
01023                 COM_FPT COM_FPW
01024                 EOS
01025 #endif
01026                 ;
01027     static VALUE pat = Qnil;
01028 
01029     REGCOMP_I(pat);
01030     SUBS(str, pat, parse_us_cb);
01031 }
01032 
01033 static int
01034 parse_iso_cb(VALUE m, VALUE hash)
01035 {
01036     VALUE y, mon, d;
01037 
01038     y = rb_reg_nth_match(1, m);
01039     mon = rb_reg_nth_match(2, m);
01040     d = rb_reg_nth_match(3, m);
01041 
01042 #ifdef TIGHT_PARSER
01043     if (!check_apost(y, mon, d))
01044         return 0;
01045 #endif
01046 
01047     s3e(hash, y, mon, d, 0);
01048     return 1;
01049 }
01050 
01051 static int
01052 parse_iso(VALUE str, VALUE hash)
01053 {
01054     static const char pat_source[] =
01055 #ifndef TIGHT_PARSER
01056         "('?[-+]?\\d+)-(\\d+)-('?-?\\d+)"
01057 #else
01058         BOS
01059         FPW_COM FPT_COM
01060         "([-+']?\\d+)-(\\d+)-([-']?\\d+)"
01061         TEE_FPT COM_FPW
01062         EOS
01063 #endif
01064         ;
01065     static VALUE pat = Qnil;
01066 
01067     REGCOMP_0(pat);
01068     SUBS(str, pat, parse_iso_cb);
01069 }
01070 
01071 static int
01072 parse_iso21_cb(VALUE m, VALUE hash)
01073 {
01074     VALUE y, w, d;
01075 
01076     y = rb_reg_nth_match(1, m);
01077     w = rb_reg_nth_match(2, m);
01078     d = rb_reg_nth_match(3, m);
01079 
01080     if (!NIL_P(y))
01081         set_hash("cwyear", str2num(y));
01082     set_hash("cweek", str2num(w));
01083     if (!NIL_P(d))
01084         set_hash("cwday", str2num(d));
01085 
01086     return 1;
01087 }
01088 
01089 static int
01090 parse_iso21(VALUE str, VALUE hash)
01091 {
01092     static const char pat_source[] =
01093 #ifndef TIGHT_PARSER
01094         "\\b(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?\\b"
01095 #else
01096         BOS
01097         FPW_COM FPT_COM
01098         "(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?"
01099         TEE_FPT COM_FPW
01100         EOS
01101 #endif
01102         ;
01103     static VALUE pat = Qnil;
01104 
01105     REGCOMP_I(pat);
01106     SUBS(str, pat, parse_iso21_cb);
01107 }
01108 
01109 static int
01110 parse_iso22_cb(VALUE m, VALUE hash)
01111 {
01112     VALUE d;
01113 
01114     d = rb_reg_nth_match(1, m);
01115     set_hash("cwday", str2num(d));
01116     return 1;
01117 }
01118 
01119 static int
01120 parse_iso22(VALUE str, VALUE hash)
01121 {
01122     static const char pat_source[] =
01123 #ifndef TIGHT_PARSER
01124         "-w-(\\d)\\b"
01125 #else
01126         BOS
01127         FPW_COM FPT_COM
01128         "-w-(\\d)"
01129         TEE_FPT COM_FPW
01130         EOS
01131 #endif
01132         ;
01133     static VALUE pat = Qnil;
01134 
01135     REGCOMP_I(pat);
01136     SUBS(str, pat, parse_iso22_cb);
01137 }
01138 
01139 static int
01140 parse_iso23_cb(VALUE m, VALUE hash)
01141 {
01142     VALUE mon, d;
01143 
01144     mon = rb_reg_nth_match(1, m);
01145     d = rb_reg_nth_match(2, m);
01146 
01147     if (!NIL_P(mon))
01148         set_hash("mon", str2num(mon));
01149     set_hash("mday", str2num(d));
01150 
01151     return 1;
01152 }
01153 
01154 static int
01155 parse_iso23(VALUE str, VALUE hash)
01156 {
01157     static const char pat_source[] =
01158 #ifndef TIGHT_PARSER
01159         "--(\\d{2})?-(\\d{2})\\b"
01160 #else
01161         BOS
01162         FPW_COM FPT_COM
01163         "--(\\d{2})?-(\\d{2})"
01164         TEE_FPT COM_FPW
01165         EOS
01166 #endif
01167         ;
01168     static VALUE pat = Qnil;
01169 
01170     REGCOMP_0(pat);
01171     SUBS(str, pat, parse_iso23_cb);
01172 }
01173 
01174 static int
01175 parse_iso24_cb(VALUE m, VALUE hash)
01176 {
01177     VALUE mon, d;
01178 
01179     mon = rb_reg_nth_match(1, m);
01180     d = rb_reg_nth_match(2, m);
01181 
01182     set_hash("mon", str2num(mon));
01183     if (!NIL_P(d))
01184         set_hash("mday", str2num(d));
01185 
01186     return 1;
01187 }
01188 
01189 static int
01190 parse_iso24(VALUE str, VALUE hash)
01191 {
01192     static const char pat_source[] =
01193 #ifndef TIGHT_PARSER
01194         "--(\\d{2})(\\d{2})?\\b"
01195 #else
01196         BOS
01197         FPW_COM FPT_COM
01198         "--(\\d{2})(\\d{2})?"
01199         TEE_FPT COM_FPW
01200         EOS
01201 #endif
01202         ;
01203     static VALUE pat = Qnil;
01204 
01205     REGCOMP_0(pat);
01206     SUBS(str, pat, parse_iso24_cb);
01207 }
01208 
01209 static int
01210 parse_iso25_cb(VALUE m, VALUE hash)
01211 {
01212     VALUE y, d;
01213 
01214     y = rb_reg_nth_match(1, m);
01215     d = rb_reg_nth_match(2, m);
01216 
01217     set_hash("year", str2num(y));
01218     set_hash("yday", str2num(d));
01219 
01220     return 1;
01221 }
01222 
01223 static int
01224 parse_iso25(VALUE str, VALUE hash)
01225 {
01226     static const char pat0_source[] =
01227 #ifndef TIGHT_PARSER
01228         "[,.](\\d{2}|\\d{4})-\\d{3}\\b"
01229 #else
01230         BOS
01231         FPW_COM FPT_COM
01232         "[,.](\\d{2}|\\d{4})-\\d{3}"
01233         TEE_FPT COM_FPW
01234         EOS
01235 #endif
01236         ;
01237     static VALUE pat0 = Qnil;
01238     static const char pat_source[] =
01239 #ifndef TIGHT_PARSER
01240         "\\b(\\d{2}|\\d{4})-(\\d{3})\\b"
01241 #else
01242         BOS
01243         FPW_COM FPT_COM
01244         "(\\d{2}|\\d{4})-(\\d{3})"
01245         TEE_FPT COM_FPW
01246         EOS
01247 #endif
01248         ;
01249     static VALUE pat = Qnil;
01250 
01251     REGCOMP_0(pat0);
01252     REGCOMP_0(pat);
01253 
01254     if (!NIL_P(f_match(pat0, str)))
01255         return 0;
01256     SUBS(str, pat, parse_iso25_cb);
01257 }
01258 
01259 static int
01260 parse_iso26_cb(VALUE m, VALUE hash)
01261 {
01262     VALUE d;
01263 
01264     d = rb_reg_nth_match(1, m);
01265     set_hash("yday", str2num(d));
01266 
01267     return 1;
01268 }
01269 static int
01270 parse_iso26(VALUE str, VALUE hash)
01271 {
01272     static const char pat0_source[] =
01273 #ifndef TIGHT_PARSER
01274         "\\d-\\d{3}\\b"
01275 #else
01276         BOS
01277         FPW_COM FPT_COM
01278         "\\d-\\d{3}"
01279         TEE_FPT COM_FPW
01280         EOS
01281 #endif
01282         ;
01283     static VALUE pat0 = Qnil;
01284     static const char pat_source[] =
01285 #ifndef TIGHT_PARSER
01286         "\\b-(\\d{3})\\b"
01287 #else
01288         BOS
01289         FPW_COM FPT_COM
01290         "-(\\d{3})"
01291         TEE_FPT COM_FPW
01292         EOS
01293 #endif
01294         ;
01295     static VALUE pat = Qnil;
01296 
01297     REGCOMP_0(pat0);
01298     REGCOMP_0(pat);
01299 
01300     if (!NIL_P(f_match(pat0, str)))
01301         return 0;
01302     SUBS(str, pat, parse_iso26_cb);
01303 }
01304 
01305 static int
01306 parse_iso2(VALUE str, VALUE hash)
01307 {
01308     if (parse_iso21(str, hash))
01309         goto ok;
01310     if (parse_iso22(str, hash))
01311         goto ok;
01312     if (parse_iso23(str, hash))
01313         goto ok;
01314     if (parse_iso24(str, hash))
01315         goto ok;
01316     if (parse_iso25(str, hash))
01317         goto ok;
01318     if (parse_iso26(str, hash))
01319         goto ok;
01320     return 0;
01321 
01322   ok:
01323     return 1;
01324 }
01325 
01326 static int
01327 gengo(int c)
01328 {
01329     int e;
01330 
01331     switch (c) {
01332       case 'M': case 'm': e = 1867; break;
01333       case 'T': case 't': e = 1911; break;
01334       case 'S': case 's': e = 1925; break;
01335       case 'H': case 'h': e = 1988; break;
01336       default:  e = 0; break;
01337     }
01338     return e;
01339 }
01340 
01341 static int
01342 parse_jis_cb(VALUE m, VALUE hash)
01343 {
01344     VALUE e, y, mon, d;
01345     int ep;
01346 
01347     e = rb_reg_nth_match(1, m);
01348     y = rb_reg_nth_match(2, m);
01349     mon = rb_reg_nth_match(3, m);
01350     d = rb_reg_nth_match(4, m);
01351 
01352     ep = gengo(*RSTRING_PTR(e));
01353 
01354     set_hash("year", f_add(str2num(y), INT2FIX(ep)));
01355     set_hash("mon", str2num(mon));
01356     set_hash("mday", str2num(d));
01357 
01358     return 1;
01359 }
01360 
01361 static int
01362 parse_jis(VALUE str, VALUE hash)
01363 {
01364     static const char pat_source[] =
01365 #ifndef TIGHT_PARSER
01366         "\\b([mtsh])(\\d+)\\.(\\d+)\\.(\\d+)"
01367 #else
01368         BOS
01369         FPW_COM FPT_COM
01370         "([mtsh])(\\d+)\\.(\\d+)\\.(\\d+)"
01371         TEE_FPT COM_FPW
01372         EOS
01373 #endif
01374         ;
01375     static VALUE pat = Qnil;
01376 
01377     REGCOMP_I(pat);
01378     SUBS(str, pat, parse_jis_cb);
01379 }
01380 
01381 static int
01382 parse_vms11_cb(VALUE m, VALUE hash)
01383 {
01384     VALUE y, mon, d;
01385 
01386     d = rb_reg_nth_match(1, m);
01387     mon = rb_reg_nth_match(2, m);
01388     y = rb_reg_nth_match(3, m);
01389 
01390 #ifdef TIGHT_PARSER
01391     if (!check_apost(d, mon, y))
01392         return 0;
01393 #endif
01394 
01395     mon = INT2FIX(mon_num(mon));
01396 
01397     s3e(hash, y, mon, d, 0);
01398     return 1;
01399 }
01400 
01401 static int
01402 parse_vms11(VALUE str, VALUE hash)
01403 {
01404     static const char pat_source[] =
01405 #ifndef TIGHT_PARSER
01406         "('?-?\\d+)-(" ABBR_MONTHS ")[^-/.]*"
01407         "-('?-?\\d+)"
01408 #else
01409         BOS
01410         FPW_COM FPT_COM
01411         "([-']?\\d+)-(" DOTLESS_VALID_MONTHS ")"
01412         "-([-']?\\d+)"
01413         COM_FPT COM_FPW
01414         EOS
01415 #endif
01416         ;
01417     static VALUE pat = Qnil;
01418 
01419     REGCOMP_I(pat);
01420     SUBS(str, pat, parse_vms11_cb);
01421 }
01422 
01423 static int
01424 parse_vms12_cb(VALUE m, VALUE hash)
01425 {
01426     VALUE y, mon, d;
01427 
01428     mon = rb_reg_nth_match(1, m);
01429     d = rb_reg_nth_match(2, m);
01430     y = rb_reg_nth_match(3, m);
01431 
01432 #ifdef TIGHT_PARSER
01433     if (!check_apost(mon, d, y))
01434         return 0;
01435 #endif
01436 
01437     mon = INT2FIX(mon_num(mon));
01438 
01439     s3e(hash, y, mon, d, 0);
01440     return 1;
01441 }
01442 
01443 static int
01444 parse_vms12(VALUE str, VALUE hash)
01445 {
01446     static const char pat_source[] =
01447 #ifndef TIGHT_PARSER
01448         "\\b(" ABBR_MONTHS ")[^-/.]*"
01449         "-('?-?\\d+)(?:-('?-?\\d+))?"
01450 #else
01451         BOS
01452         FPW_COM FPT_COM
01453         "(" DOTLESS_VALID_MONTHS ")"
01454         "-([-']?\\d+)(?:-([-']?\\d+))?"
01455         COM_FPT COM_FPW
01456         EOS
01457 #endif
01458         ;
01459     static VALUE pat = Qnil;
01460 
01461     REGCOMP_I(pat);
01462     SUBS(str, pat, parse_vms12_cb);
01463 }
01464 
01465 static int
01466 parse_vms(VALUE str, VALUE hash)
01467 {
01468     if (parse_vms11(str, hash))
01469         goto ok;
01470     if (parse_vms12(str, hash))
01471         goto ok;
01472     return 0;
01473 
01474   ok:
01475     return 1;
01476 }
01477 
01478 static int
01479 parse_sla_cb(VALUE m, VALUE hash)
01480 {
01481     VALUE y, mon, d;
01482 
01483     y = rb_reg_nth_match(1, m);
01484     mon = rb_reg_nth_match(2, m);
01485     d = rb_reg_nth_match(3, m);
01486 
01487 #ifdef TIGHT_PARSER
01488     if (!check_apost(y, mon, d))
01489         return 0;
01490 #endif
01491 
01492     s3e(hash, y, mon, d, 0);
01493     return 1;
01494 }
01495 
01496 static int
01497 parse_sla(VALUE str, VALUE hash)
01498 {
01499     static const char pat_source[] =
01500 #ifndef TIGHT_PARSER
01501         "('?-?\\d+)/\\s*('?\\d+)(?:\\D\\s*('?-?\\d+))?"
01502 #else
01503         BOS
01504         FPW_COM FPT_COM
01505         "([-']?\\d+)/\\s*('?\\d+)(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?"
01506         COM_FPT COM_FPW
01507         EOS
01508 #endif
01509         ;
01510     static VALUE pat = Qnil;
01511 
01512     REGCOMP_I(pat);
01513     SUBS(str, pat, parse_sla_cb);
01514 }
01515 
01516 #ifdef TIGHT_PARSER
01517 static int
01518 parse_sla2_cb(VALUE m, VALUE hash)
01519 {
01520     VALUE y, mon, d;
01521 
01522     d = rb_reg_nth_match(1, m);
01523     mon = rb_reg_nth_match(2, m);
01524     y = rb_reg_nth_match(3, m);
01525 
01526     if (!check_apost(d, mon, y))
01527         return 0;
01528 
01529     mon = INT2FIX(mon_num(mon));
01530 
01531     s3e(hash, y, mon, d, 0);
01532     return 1;
01533 }
01534 
01535 static int
01536 parse_sla2(VALUE str, VALUE hash)
01537 {
01538     static const char pat_source[] =
01539         BOS
01540         FPW_COM FPT_COM
01541         "([-']?\\d+)/\\s*(" DOTLESS_VALID_MONTHS ")(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?"
01542         COM_FPT COM_FPW
01543         EOS
01544         ;
01545     static VALUE pat = Qnil;
01546 
01547     REGCOMP_I(pat);
01548     SUBS(str, pat, parse_sla2_cb);
01549 }
01550 
01551 static int
01552 parse_sla3_cb(VALUE m, VALUE hash)
01553 {
01554     VALUE y, mon, d;
01555 
01556     mon = rb_reg_nth_match(1, m);
01557     d = rb_reg_nth_match(2, m);
01558     y = rb_reg_nth_match(3, m);
01559 
01560     if (!check_apost(mon, d, y))
01561         return 0;
01562 
01563     mon = INT2FIX(mon_num(mon));
01564 
01565     s3e(hash, y, mon, d, 0);
01566     return 1;
01567 }
01568 
01569 static int
01570 parse_sla3(VALUE str, VALUE hash)
01571 {
01572     static const char pat_source[] =
01573         BOS
01574         FPW_COM FPT_COM
01575         "(" DOTLESS_VALID_MONTHS ")/\\s*([-']?\\d+)(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?"
01576         COM_FPT COM_FPW
01577         EOS
01578         ;
01579     static VALUE pat = Qnil;
01580 
01581     REGCOMP_I(pat);
01582     SUBS(str, pat, parse_sla3_cb);
01583 }
01584 #endif
01585 
01586 static int
01587 parse_dot_cb(VALUE m, VALUE hash)
01588 {
01589     VALUE y, mon, d;
01590 
01591     y = rb_reg_nth_match(1, m);
01592     mon = rb_reg_nth_match(2, m);
01593     d = rb_reg_nth_match(3, m);
01594 
01595 #ifdef TIGHT_PARSER
01596     if (!check_apost(y, mon, d))
01597         return 0;
01598 #endif
01599 
01600     s3e(hash, y, mon, d, 0);
01601     return 1;
01602 }
01603 
01604 static int
01605 parse_dot(VALUE str, VALUE hash)
01606 {
01607     static const char pat_source[] =
01608 #ifndef TIGHT_PARSER
01609         "('?-?\\d+)\\.\\s*('?\\d+)\\.\\s*('?-?\\d+)"
01610 #else
01611         BOS
01612         FPW_COM FPT_COM
01613         "([-']?\\d+)\\.\\s*(\\d+)\\.\\s*([-']?\\d+)"
01614         COM_FPT COM_FPW
01615         EOS
01616 #endif
01617         ;
01618     static VALUE pat = Qnil;
01619 
01620     REGCOMP_I(pat);
01621     SUBS(str, pat, parse_dot_cb);
01622 }
01623 
01624 #ifdef TIGHT_PARSER
01625 static int
01626 parse_dot2_cb(VALUE m, VALUE hash)
01627 {
01628     VALUE y, mon, d;
01629 
01630     d = rb_reg_nth_match(1, m);
01631     mon = rb_reg_nth_match(2, m);
01632     y = rb_reg_nth_match(3, m);
01633 
01634     if (!check_apost(d, mon, y))
01635         return 0;
01636 
01637     mon = INT2FIX(mon_num(mon));
01638 
01639     s3e(hash, y, mon, d, 0);
01640     return 1;
01641 }
01642 
01643 static int
01644 parse_dot2(VALUE str, VALUE hash)
01645 {
01646     static const char pat_source[] =
01647         BOS
01648         FPW_COM FPT_COM
01649         "([-']?\\d+)\\.\\s*(" DOTLESS_VALID_MONTHS ")(?:(?:[./])\\s*([-']?\\d+))?"
01650         COM_FPT COM_FPW
01651         EOS
01652         ;
01653     static VALUE pat = Qnil;
01654 
01655     REGCOMP_I(pat);
01656     SUBS(str, pat, parse_dot2_cb);
01657 }
01658 
01659 static int
01660 parse_dot3_cb(VALUE m, VALUE hash)
01661 {
01662     VALUE y, mon, d;
01663 
01664     mon = rb_reg_nth_match(1, m);
01665     d = rb_reg_nth_match(2, m);
01666     y = rb_reg_nth_match(3, m);
01667 
01668     if (!check_apost(mon, d, y))
01669         return 0;
01670 
01671     mon = INT2FIX(mon_num(mon));
01672 
01673     s3e(hash, y, mon, d, 0);
01674     return 1;
01675 }
01676 
01677 static int
01678 parse_dot3(VALUE str, VALUE hash)
01679 {
01680     static const char pat_source[] =
01681         BOS
01682         FPW_COM FPT_COM
01683         "(" DOTLESS_VALID_MONTHS ")\\.\\s*([-']?\\d+)(?:(?:[./])\\s*([-']?\\d+))?"
01684         COM_FPT COM_FPW
01685         EOS
01686         ;
01687     static VALUE pat = Qnil;
01688 
01689     REGCOMP_I(pat);
01690     SUBS(str, pat, parse_dot3_cb);
01691 }
01692 #endif
01693 
01694 static int
01695 parse_year_cb(VALUE m, VALUE hash)
01696 {
01697     VALUE y;
01698 
01699     y = rb_reg_nth_match(1, m);
01700     set_hash("year", str2num(y));
01701     return 1;
01702 }
01703 
01704 static int
01705 parse_year(VALUE str, VALUE hash)
01706 {
01707     static const char pat_source[] =
01708 #ifndef TIGHT_PARSER
01709         "'(\\d+)\\b"
01710 #else
01711         BOS
01712         FPW_COM FPT_COM
01713         "'(\\d+)"
01714         COM_FPT COM_FPW
01715         EOS
01716 #endif
01717         ;
01718     static VALUE pat = Qnil;
01719 
01720     REGCOMP_0(pat);
01721     SUBS(str, pat, parse_year_cb);
01722 }
01723 
01724 static int
01725 parse_mon_cb(VALUE m, VALUE hash)
01726 {
01727     VALUE mon;
01728 
01729     mon = rb_reg_nth_match(1, m);
01730     set_hash("mon", INT2FIX(mon_num(mon)));
01731     return 1;
01732 }
01733 
01734 static int
01735 parse_mon(VALUE str, VALUE hash)
01736 {
01737     static const char pat_source[] =
01738 #ifndef TIGHT_PARSER
01739         "\\b(" ABBR_MONTHS ")\\S*"
01740 #else
01741         BOS
01742         FPW_COM FPT_COM
01743         "(" VALID_MONTHS ")"
01744         COM_FPT COM_FPW
01745         EOS
01746 #endif
01747         ;
01748     static VALUE pat = Qnil;
01749 
01750     REGCOMP_I(pat);
01751     SUBS(str, pat, parse_mon_cb);
01752 }
01753 
01754 static int
01755 parse_mday_cb(VALUE m, VALUE hash)
01756 {
01757     VALUE d;
01758 
01759     d = rb_reg_nth_match(1, m);
01760     set_hash("mday", str2num(d));
01761     return 1;
01762 }
01763 
01764 static int
01765 parse_mday(VALUE str, VALUE hash)
01766 {
01767     static const char pat_source[] =
01768 #ifndef TIGHT_PARSER
01769         "(\\d+)(st|nd|rd|th)\\b"
01770 #else
01771         BOS
01772         FPW_COM FPT_COM
01773         "(\\d+)(st|nd|rd|th)"
01774         COM_FPT COM_FPW
01775         EOS
01776 #endif
01777         ;
01778     static VALUE pat = Qnil;
01779 
01780     REGCOMP_I(pat);
01781     SUBS(str, pat, parse_mday_cb);
01782 }
01783 
01784 static int
01785 n2i(const char *s, long f, long w)
01786 {
01787     long e, i;
01788     int v;
01789 
01790     e = f + w;
01791     v = 0;
01792     for (i = f; i < e; i++) {
01793         v *= 10;
01794         v += s[i] - '0';
01795     }
01796     return v;
01797 }
01798 
01799 static int
01800 parse_ddd_cb(VALUE m, VALUE hash)
01801 {
01802     VALUE s1, s2, s3, s4, s5;
01803     const char *cs2, *cs3, *cs5;
01804     long l2, l3, l4, l5;
01805 
01806     s1 = rb_reg_nth_match(1, m);
01807     s2 = rb_reg_nth_match(2, m);
01808     s3 = rb_reg_nth_match(3, m);
01809     s4 = rb_reg_nth_match(4, m);
01810     s5 = rb_reg_nth_match(5, m);
01811 
01812     cs2 = RSTRING_PTR(s2);
01813     l2 = RSTRING_LEN(s2);
01814 
01815     switch (l2) {
01816       case 2:
01817         if (NIL_P(s3) && !NIL_P(s4))
01818             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01819         else
01820             set_hash("mday", INT2FIX(n2i(cs2,    0, 2)));
01821         break;
01822       case 4:
01823         if (NIL_P(s3) && !NIL_P(s4)) {
01824             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01825             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01826         }
01827         else {
01828             set_hash("mon",  INT2FIX(n2i(cs2,    0, 2)));
01829             set_hash("mday", INT2FIX(n2i(cs2,    2, 2)));
01830         }
01831         break;
01832       case 6:
01833         if (NIL_P(s3) && !NIL_P(s4)) {
01834             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01835             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01836             set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
01837         }
01838         else {
01839             int                  y = n2i(cs2,    0, 2);
01840             if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01841                 y = -y;
01842             set_hash("year", INT2FIX(y));
01843             set_hash("mon",  INT2FIX(n2i(cs2,    2, 2)));
01844             set_hash("mday", INT2FIX(n2i(cs2,    4, 2)));
01845         }
01846         break;
01847       case 8:
01848       case 10:
01849       case 12:
01850       case 14:
01851         if (NIL_P(s3) && !NIL_P(s4)) {
01852             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01853             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01854             set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
01855             set_hash("mday", INT2FIX(n2i(cs2, l2-8, 2)));
01856             if (l2 >= 10)
01857                 set_hash("mon", INT2FIX(n2i(cs2, l2-10, 2)));
01858             if (l2 == 12) {
01859                 int y = n2i(cs2, l2-12, 2);
01860                 if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01861                     y = -y;
01862                 set_hash("year", INT2FIX(y));
01863             }
01864             if (l2 == 14) {
01865                 int y = n2i(cs2, l2-14, 4);
01866                 if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01867                     y = -y;
01868                 set_hash("year", INT2FIX(y));
01869                 set_hash("_comp", Qfalse);
01870             }
01871         }
01872         else {
01873             int                  y = n2i(cs2,    0, 4);
01874             if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01875                 y = -y;
01876             set_hash("year", INT2FIX(y));
01877             set_hash("mon",  INT2FIX(n2i(cs2,    4, 2)));
01878             set_hash("mday", INT2FIX(n2i(cs2,    6, 2)));
01879             if (l2 >= 10)
01880                 set_hash("hour", INT2FIX(n2i(cs2,    8, 2)));
01881             if (l2 >= 12)
01882                 set_hash("min",  INT2FIX(n2i(cs2,   10, 2)));
01883             if (l2 >= 14)
01884                 set_hash("sec",  INT2FIX(n2i(cs2,   12, 2)));
01885             set_hash("_comp", Qfalse);
01886         }
01887         break;
01888       case 3:
01889         if (NIL_P(s3) && !NIL_P(s4)) {
01890             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01891             set_hash("min",  INT2FIX(n2i(cs2, l2-3, 1)));
01892         }
01893         else
01894             set_hash("yday", INT2FIX(n2i(cs2,    0, 3)));
01895         break;
01896       case 5:
01897         if (NIL_P(s3) && !NIL_P(s4)) {
01898             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01899             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01900             set_hash("hour", INT2FIX(n2i(cs2, l2-5, 1)));
01901         }
01902         else {
01903             int                  y = n2i(cs2,    0, 2);
01904             if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01905                 y = -y;
01906             set_hash("year", INT2FIX(y));
01907             set_hash("yday", INT2FIX(n2i(cs2,    2, 3)));
01908         }
01909         break;
01910       case 7:
01911         if (NIL_P(s3) && !NIL_P(s4)) {
01912             set_hash("sec",  INT2FIX(n2i(cs2, l2-2, 2)));
01913             set_hash("min",  INT2FIX(n2i(cs2, l2-4, 2)));
01914             set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
01915             set_hash("mday", INT2FIX(n2i(cs2, l2-7, 1)));
01916         }
01917         else {
01918             int                  y = n2i(cs2,    0, 4);
01919             if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
01920                 y = -y;
01921             set_hash("year", INT2FIX(y));
01922             set_hash("yday", INT2FIX(n2i(cs2,    4, 3)));
01923         }
01924         break;
01925     }
01926     RB_GC_GUARD(s2);
01927     if (!NIL_P(s3)) {
01928         cs3 = RSTRING_PTR(s3);
01929         l3 = RSTRING_LEN(s3);
01930 
01931         if (!NIL_P(s4)) {
01932             switch (l3) {
01933               case 2:
01934               case 4:
01935               case 6:
01936                 set_hash("sec", INT2FIX(n2i(cs3, l3-2, 2)));
01937                 if (l3 >= 4)
01938                     set_hash("min", INT2FIX(n2i(cs3, l3-4, 2)));
01939                 if (l3 >= 6)
01940                     set_hash("hour", INT2FIX(n2i(cs3, l3-6, 2)));
01941                 break;
01942             }
01943         }
01944         else {
01945             switch (l3) {
01946               case 2:
01947               case 4:
01948               case 6:
01949                 set_hash("hour", INT2FIX(n2i(cs3, 0, 2)));
01950                 if (l3 >= 4)
01951                     set_hash("min", INT2FIX(n2i(cs3, 2, 2)));
01952                 if (l3 >= 6)
01953                     set_hash("sec", INT2FIX(n2i(cs3, 4, 2)));
01954                 break;
01955             }
01956         }
01957         RB_GC_GUARD(s3);
01958     }
01959     if (!NIL_P(s4)) {
01960         l4 = RSTRING_LEN(s4);
01961 
01962         set_hash("sec_fraction",
01963                  rb_rational_new2(str2num(s4),
01964                                   f_expt(INT2FIX(10), LONG2NUM(l4))));
01965     }
01966     if (!NIL_P(s5)) {
01967         cs5 = RSTRING_PTR(s5);
01968         l5 = RSTRING_LEN(s5);
01969 
01970         set_hash("zone", s5);
01971 
01972         if (*cs5 == '[') {
01973             char *buf = ALLOCA_N(char, l5 + 1);
01974             char *s1, *s2, *s3;
01975             VALUE zone;
01976 
01977             memcpy(buf, cs5, l5);
01978             buf[l5 - 1] = '\0';
01979 
01980             s1 = buf + 1;
01981             s2 = strchr(buf, ':');
01982             if (s2) {
01983                 *s2 = '\0';
01984                 s2++;
01985             }
01986             if (s2)
01987                 s3 = s2;
01988             else
01989                 s3 = s1;
01990             zone = rb_str_new2(s3);
01991             set_hash("zone", zone);
01992             if (isdigit((unsigned char)*s1))
01993                 *--s1 = '+';
01994             set_hash("offset", date_zone_to_diff(rb_str_new2(s1)));
01995         }
01996         RB_GC_GUARD(s5);
01997     }
01998 
01999     return 1;
02000 }
02001 
02002 static int
02003 parse_ddd(VALUE str, VALUE hash)
02004 {
02005     static const char pat_source[] =
02006 #ifdef TIGHT_PARSER
02007                 BOS
02008 #endif
02009                 "([-+]?)(\\d{2,14})"
02010                   "(?:"
02011                     "\\s*"
02012                     "t?"
02013                     "\\s*"
02014                     "(\\d{2,6})?(?:[,.](\\d*))?"
02015                   ")?"
02016                   "(?:"
02017                     "\\s*"
02018                     "("
02019                       "z\\b"
02020                     "|"
02021                       "[-+]\\d{1,4}\\b"
02022                     "|"
02023                       "\\[[-+]?\\d[^\\]]*\\]"
02024                     ")"
02025                 ")?"
02026 #ifdef TIGHT_PARSER
02027                 EOS
02028 #endif
02029                 ;
02030     static VALUE pat = Qnil;
02031 
02032     REGCOMP_I(pat);
02033     SUBS(str, pat, parse_ddd_cb);
02034 }
02035 
02036 #ifndef TIGHT_PARSER
02037 static int
02038 parse_bc_cb(VALUE m, VALUE hash)
02039 {
02040     set_hash("_bc", Qtrue);
02041     return 1;
02042 }
02043 
02044 static int
02045 parse_bc(VALUE str, VALUE hash)
02046 {
02047     static const char pat_source[] =
02048         "\\b(bc\\b|bce\\b|b\\.c\\.|b\\.c\\.e\\.)";
02049     static VALUE pat = Qnil;
02050 
02051     REGCOMP_I(pat);
02052     SUBS(str, pat, parse_bc_cb);
02053 }
02054 
02055 static int
02056 parse_frag_cb(VALUE m, VALUE hash)
02057 {
02058     VALUE s, n;
02059 
02060     s = rb_reg_nth_match(1, m);
02061 
02062     if (!NIL_P(ref_hash("hour")) && NIL_P(ref_hash("mday"))) {
02063         n = str2num(s);
02064         if (f_ge_p(n, INT2FIX(1)) &&
02065             f_le_p(n, INT2FIX(31)))
02066             set_hash("mday", n);
02067     }
02068     if (!NIL_P(ref_hash("mday")) && NIL_P(ref_hash("hour"))) {
02069         n = str2num(s);
02070         if (f_ge_p(n, INT2FIX(0)) &&
02071             f_le_p(n, INT2FIX(24)))
02072             set_hash("hour", n);
02073     }
02074 
02075     return 1;
02076 }
02077 
02078 static int
02079 parse_frag(VALUE str, VALUE hash)
02080 {
02081     static const char pat_source[] = "\\A\\s*(\\d{1,2})\\s*\\z";
02082     static VALUE pat = Qnil;
02083 
02084     REGCOMP_I(pat);
02085     SUBS(str, pat, parse_frag_cb);
02086 }
02087 #endif
02088 
02089 #ifdef TIGHT_PARSER
02090 static int
02091 parse_dummy_cb(VALUE m, VALUE hash)
02092 {
02093     return 1;
02094 }
02095 
02096 static int
02097 parse_wday_only(VALUE str, VALUE hash)
02098 {
02099     static const char pat_source[] = "\\A\\s*" FPW "\\s*\\z";
02100     static VALUE pat = Qnil;
02101 
02102     REGCOMP_0(pat);
02103     SUBS(str, pat, parse_dummy_cb);
02104 }
02105 
02106 static int
02107 parse_time_only(VALUE str, VALUE hash)
02108 {
02109     static const char pat_source[] = "\\A\\s*" FPT "\\s*\\z";
02110     static VALUE pat = Qnil;
02111 
02112     REGCOMP_0(pat);
02113     SUBS(str, pat, parse_dummy_cb);
02114 }
02115 
02116 static int
02117 parse_wday_and_time(VALUE str, VALUE hash)
02118 {
02119     static const char pat_source[] = "\\A\\s*(" FPW "\\s+" FPT "|" FPT "\\s+" FPW ")\\s*\\z";
02120     static VALUE pat = Qnil;
02121 
02122     REGCOMP_0(pat);
02123     SUBS(str, pat, parse_dummy_cb);
02124 }
02125 
02126 static unsigned
02127 have_invalid_char_p(VALUE s)
02128 {
02129     long i;
02130 
02131     for (i = 0; i < RSTRING_LEN(s); i++)
02132         if (iscntrl((unsigned char)RSTRING_PTR(s)[i]) &&
02133             !isspace((unsigned char)RSTRING_PTR(s)[i]))
02134             return 1;
02135     return 0;
02136 }
02137 #endif
02138 
02139 #define HAVE_ALPHA (1<<0)
02140 #define HAVE_DIGIT (1<<1)
02141 #define HAVE_DASH (1<<2)
02142 #define HAVE_DOT (1<<3)
02143 #define HAVE_SLASH (1<<4)
02144 
02145 static unsigned
02146 check_class(VALUE s)
02147 {
02148     unsigned flags;
02149     long i;
02150 
02151     flags = 0;
02152     for (i = 0; i < RSTRING_LEN(s); i++) {
02153         if (isalpha((unsigned char)RSTRING_PTR(s)[i]))
02154             flags |= HAVE_ALPHA;
02155         if (isdigit((unsigned char)RSTRING_PTR(s)[i]))
02156             flags |= HAVE_DIGIT;
02157         if (RSTRING_PTR(s)[i] == '-')
02158             flags |= HAVE_DASH;
02159         if (RSTRING_PTR(s)[i] == '.')
02160             flags |= HAVE_DOT;
02161         if (RSTRING_PTR(s)[i] == '/')
02162             flags |= HAVE_SLASH;
02163     }
02164     return flags;
02165 }
02166 
02167 #define HAVE_ELEM_P(x) ((check_class(str) & (x)) == (x))
02168 
02169 #ifdef TIGHT_PARSER
02170 #define PARSER_ERROR return rb_hash_new()
02171 #endif
02172 
02173 VALUE
02174 date__parse(VALUE str, VALUE comp)
02175 {
02176     VALUE backref, hash;
02177 
02178 #ifdef TIGHT_PARSER
02179     if (have_invalid_char_p(str))
02180         PARSER_ERROR;
02181 #endif
02182 
02183     backref = rb_backref_get();
02184     rb_match_busy(backref);
02185 
02186     {
02187         static const char pat_source[] =
02188 #ifndef TIGHT_PARSER
02189             "[^-+',./:@[:alnum:]\\[\\]]+"
02190 #else
02191             "[^[:graph:]]+"
02192 #endif
02193             ;
02194         static VALUE pat = Qnil;
02195 
02196         REGCOMP_0(pat);
02197         str = rb_str_dup(str);
02198         f_gsub_bang(str, pat, asp_string());
02199     }
02200 
02201     hash = rb_hash_new();
02202     set_hash("_comp", comp);
02203 
02204     if (HAVE_ELEM_P(HAVE_ALPHA))
02205         parse_day(str, hash);
02206     if (HAVE_ELEM_P(HAVE_DIGIT))
02207         parse_time(str, hash);
02208 
02209 #ifdef TIGHT_PARSER
02210     if (HAVE_ELEM_P(HAVE_ALPHA))
02211         parse_era(str, hash);
02212 #endif
02213 
02214     if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT)) {
02215         if (parse_eu(str, hash))
02216             goto ok;
02217         if (parse_us(str, hash))
02218             goto ok;
02219     }
02220     if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DASH))
02221         if (parse_iso(str, hash))
02222             goto ok;
02223     if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DOT))
02224         if (parse_jis(str, hash))
02225             goto ok;
02226     if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_DASH))
02227         if (parse_vms(str, hash))
02228             goto ok;
02229     if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_SLASH))
02230         if (parse_sla(str, hash))
02231             goto ok;
02232 #ifdef TIGHT_PARSER
02233     if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_SLASH)) {
02234         if (parse_sla2(str, hash))
02235             goto ok;
02236         if (parse_sla3(str, hash))
02237             goto ok;
02238     }
02239 #endif
02240     if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DOT))
02241         if (parse_dot(str, hash))
02242             goto ok;
02243 #ifdef TIGHT_PARSER
02244     if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_DOT)) {
02245         if (parse_dot2(str, hash))
02246             goto ok;
02247         if (parse_dot3(str, hash))
02248             goto ok;
02249     }
02250 #endif
02251     if (HAVE_ELEM_P(HAVE_DIGIT))
02252         if (parse_iso2(str, hash))
02253             goto ok;
02254     if (HAVE_ELEM_P(HAVE_DIGIT))
02255         if (parse_year(str, hash))
02256             goto ok;
02257     if (HAVE_ELEM_P(HAVE_ALPHA))
02258         if (parse_mon(str, hash))
02259             goto ok;
02260     if (HAVE_ELEM_P(HAVE_DIGIT))
02261         if (parse_mday(str, hash))
02262             goto ok;
02263     if (HAVE_ELEM_P(HAVE_DIGIT))
02264         if (parse_ddd(str, hash))
02265             goto ok;
02266 
02267 #ifdef TIGHT_PARSER
02268     if (parse_wday_only(str, hash))
02269         goto ok;
02270     if (parse_time_only(str, hash))
02271             goto ok;
02272     if (parse_wday_and_time(str, hash))
02273         goto ok;
02274 
02275     PARSER_ERROR; /* not found */
02276 #endif
02277 
02278   ok:
02279 #ifndef TIGHT_PARSER
02280     if (HAVE_ELEM_P(HAVE_ALPHA))
02281         parse_bc(str, hash);
02282     if (HAVE_ELEM_P(HAVE_DIGIT))
02283         parse_frag(str, hash);
02284 #endif
02285 
02286     {
02287         if (RTEST(ref_hash("_bc"))) {
02288             VALUE y;
02289 
02290             y = ref_hash("cwyear");
02291             if (!NIL_P(y)) {
02292                 y = f_add(f_negate(y), INT2FIX(1));
02293                 set_hash("cwyear", y);
02294             }
02295             y = ref_hash("year");
02296             if (!NIL_P(y)) {
02297                 y = f_add(f_negate(y), INT2FIX(1));
02298                 set_hash("year", y);
02299             }
02300         }
02301 
02302         if (RTEST(ref_hash("_comp"))) {
02303             VALUE y;
02304 
02305             y = ref_hash("cwyear");
02306             if (!NIL_P(y))
02307                 if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) {
02308                     if (f_ge_p(y, INT2FIX(69)))
02309                         set_hash("cwyear", f_add(y, INT2FIX(1900)));
02310                     else
02311                         set_hash("cwyear", f_add(y, INT2FIX(2000)));
02312                 }
02313             y = ref_hash("year");
02314             if (!NIL_P(y))
02315                 if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) {
02316                     if (f_ge_p(y, INT2FIX(69)))
02317                         set_hash("year", f_add(y, INT2FIX(1900)));
02318                     else
02319                         set_hash("year", f_add(y, INT2FIX(2000)));
02320                 }
02321         }
02322 
02323     }
02324 
02325     del_hash("_bc");
02326     del_hash("_comp");
02327 
02328     {
02329         VALUE zone = ref_hash("zone");
02330         if (!NIL_P(zone) && NIL_P(ref_hash("offset")))
02331             set_hash("offset", date_zone_to_diff(zone));
02332     }
02333 
02334     rb_backref_set(backref);
02335 
02336     return hash;
02337 }
02338 
02339 static VALUE
02340 comp_year69(VALUE y)
02341 {
02342     if (f_ge_p(y, INT2FIX(69)))
02343         return f_add(y, INT2FIX(1900));
02344     return f_add(y, INT2FIX(2000));
02345 }
02346 
02347 static VALUE
02348 comp_year50(VALUE y)
02349 {
02350     if (f_ge_p(y, INT2FIX(50)))
02351         return f_add(y, INT2FIX(1900));
02352     return f_add(y, INT2FIX(2000));
02353 }
02354 
02355 static VALUE
02356 sec_fraction(VALUE f)
02357 {
02358     return rb_rational_new2(str2num(f),
02359                             f_expt(INT2FIX(10),
02360                                    LONG2NUM(RSTRING_LEN(f))));
02361 }
02362 
02363 #define SNUM 14
02364 
02365 static int
02366 iso8601_ext_datetime_cb(VALUE m, VALUE hash)
02367 {
02368     VALUE s[SNUM + 1], y;
02369 
02370     {
02371         int i;
02372         s[0] = Qnil;
02373         for (i = 1; i <= SNUM; i++)
02374             s[i] = rb_reg_nth_match(i, m);
02375     }
02376 
02377     if (!NIL_P(s[3])) {
02378         set_hash("mday", str2num(s[3]));
02379         if (strcmp(RSTRING_PTR(s[1]), "-") != 0) {
02380             y = str2num(s[1]);
02381             if (RSTRING_LEN(s[1]) < 4)
02382                 y = comp_year69(y);
02383             set_hash("year", y);
02384         }
02385         if (NIL_P(s[2])) {
02386             if (strcmp(RSTRING_PTR(s[1]), "-") != 0)
02387                 return 0;
02388         }
02389         else
02390             set_hash("mon", str2num(s[2]));
02391     }
02392     else if (!NIL_P(s[5])) {
02393         set_hash("yday", str2num(s[5]));
02394         if (!NIL_P(s[4])) {
02395             y = str2num(s[4]);
02396             if (RSTRING_LEN(s[4]) < 4)
02397                 y = comp_year69(y);
02398             set_hash("year", y);
02399         }
02400     }
02401     else if (!NIL_P(s[8])) {
02402         set_hash("cweek", str2num(s[7]));
02403         set_hash("cwday", str2num(s[8]));
02404         if (!NIL_P(s[6])) {
02405             y = str2num(s[6]);
02406             if (RSTRING_LEN(s[6]) < 4)
02407                 y = comp_year69(y);
02408             set_hash("cwyear", y);
02409         }
02410     }
02411     else if (!NIL_P(s[9])) {
02412         set_hash("cwday", str2num(s[9]));
02413     }
02414     if (!NIL_P(s[10])) {
02415         set_hash("hour", str2num(s[10]));
02416         set_hash("min", str2num(s[11]));
02417         if (!NIL_P(s[12]))
02418             set_hash("sec", str2num(s[12]));
02419     }
02420     if (!NIL_P(s[13])) {
02421         set_hash("sec_fraction", sec_fraction(s[13]));
02422     }
02423     if (!NIL_P(s[14])) {
02424         set_hash("zone", s[14]);
02425         set_hash("offset", date_zone_to_diff(s[14]));
02426     }
02427 
02428     return 1;
02429 }
02430 
02431 static int
02432 iso8601_ext_datetime(VALUE str, VALUE hash)
02433 {
02434     static const char pat_source[] =
02435         "\\A\\s*(?:([-+]?\\d{2,}|-)-(\\d{2})?-(\\d{2})|"
02436                 "([-+]?\\d{2,})?-(\\d{3})|"
02437                 "(\\d{4}|\\d{2})?-w(\\d{2})-(\\d)|"
02438                 "-w-(\\d))"
02439         "(?:t"
02440         "(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?)?"
02441         "(z|[-+]\\d{2}(?::?\\d{2})?)?)?\\s*\\z";
02442     static VALUE pat = Qnil;
02443 
02444     REGCOMP_I(pat);
02445     MATCH(str, pat, iso8601_ext_datetime_cb);
02446 }
02447 
02448 #undef SNUM
02449 #define SNUM 17
02450 
02451 static int
02452 iso8601_bas_datetime_cb(VALUE m, VALUE hash)
02453 {
02454     VALUE s[SNUM + 1], y;
02455 
02456     {
02457         int i;
02458         s[0] = Qnil;
02459         for (i = 1; i <= SNUM; i++)
02460             s[i] = rb_reg_nth_match(i, m);
02461     }
02462 
02463     if (!NIL_P(s[3])) {
02464         set_hash("mday", str2num(s[3]));
02465         if (strcmp(RSTRING_PTR(s[1]), "--") != 0) {
02466             y = str2num(s[1]);
02467             if (RSTRING_LEN(s[1]) < 4)
02468                 y = comp_year69(y);
02469             set_hash("year", y);
02470         }
02471         if (*RSTRING_PTR(s[2]) == '-') {
02472             if (strcmp(RSTRING_PTR(s[1]), "--") != 0)
02473                 return 0;
02474         }
02475         else
02476             set_hash("mon", str2num(s[2]));
02477     }
02478     else if (!NIL_P(s[5])) {
02479         set_hash("yday", str2num(s[5]));
02480         y = str2num(s[4]);
02481         if (RSTRING_LEN(s[4]) < 4)
02482             y = comp_year69(y);
02483         set_hash("year", y);
02484     }
02485     else if (!NIL_P(s[6])) {
02486         set_hash("yday", str2num(s[6]));
02487     }
02488     else if (!NIL_P(s[9])) {
02489         set_hash("cweek", str2num(s[8]));
02490         set_hash("cwday", str2num(s[9]));
02491         y = str2num(s[7]);
02492         if (RSTRING_LEN(s[7]) < 4)
02493             y = comp_year69(y);
02494         set_hash("cwyear", y);
02495     }
02496     else if (!NIL_P(s[11])) {
02497         set_hash("cweek", str2num(s[10]));
02498         set_hash("cwday", str2num(s[11]));
02499     }
02500     else if (!NIL_P(s[12])) {
02501         set_hash("cwday", str2num(s[12]));
02502     }
02503     if (!NIL_P(s[13])) {
02504         set_hash("hour", str2num(s[13]));
02505         set_hash("min", str2num(s[14]));
02506         if (!NIL_P(s[15]))
02507             set_hash("sec", str2num(s[15]));
02508     }
02509     if (!NIL_P(s[16])) {
02510         set_hash("sec_fraction", sec_fraction(s[16]));
02511     }
02512     if (!NIL_P(s[17])) {
02513         set_hash("zone", s[17]);
02514         set_hash("offset", date_zone_to_diff(s[17]));
02515     }
02516 
02517     return 1;
02518 }
02519 
02520 static int
02521 iso8601_bas_datetime(VALUE str, VALUE hash)
02522 {
02523     static const char pat_source[] =
02524         "\\A\\s*(?:([-+]?(?:\\d{4}|\\d{2})|--)(\\d{2}|-)(\\d{2})|"
02525                    "([-+]?(?:\\d{4}|\\d{2}))(\\d{3})|"
02526                    "-(\\d{3})|"
02527                    "(\\d{4}|\\d{2})w(\\d{2})(\\d)|"
02528                    "-w(\\d{2})(\\d)|"
02529                    "-w-(\\d))"
02530         "(?:t?"
02531         "(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?)?"
02532         "(z|[-+]\\d{2}(?:\\d{2})?)?)?\\s*\\z";
02533     static VALUE pat = Qnil;
02534 
02535     REGCOMP_I(pat);
02536     MATCH(str, pat, iso8601_bas_datetime_cb);
02537 }
02538 
02539 #undef SNUM
02540 #define SNUM 5
02541 
02542 static int
02543 iso8601_ext_time_cb(VALUE m, VALUE hash)
02544 {
02545     VALUE s[SNUM + 1];
02546 
02547     {
02548         int i;
02549         s[0] = Qnil;
02550         for (i = 1; i <= SNUM; i++)
02551             s[i] = rb_reg_nth_match(i, m);
02552     }
02553 
02554     set_hash("hour", str2num(s[1]));
02555     set_hash("min", str2num(s[2]));
02556     if (!NIL_P(s[3]))
02557         set_hash("sec", str2num(s[3]));
02558     if (!NIL_P(s[4]))
02559         set_hash("sec_fraction", sec_fraction(s[4]));
02560     if (!NIL_P(s[5])) {
02561         set_hash("zone", s[5]);
02562         set_hash("offset", date_zone_to_diff(s[5]));
02563     }
02564 
02565     return 1;
02566 }
02567 
02568 #define iso8601_bas_time_cb iso8601_ext_time_cb
02569 
02570 static int
02571 iso8601_ext_time(VALUE str, VALUE hash)
02572 {
02573     static const char pat_source[] =
02574         "\\A\\s*(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?"
02575         "(z|[-+]\\d{2}(:?\\d{2})?)?)?\\s*\\z";
02576     static VALUE pat = Qnil;
02577 
02578     REGCOMP_I(pat);
02579     MATCH(str, pat, iso8601_ext_time_cb);
02580 }
02581 
02582 static int
02583 iso8601_bas_time(VALUE str, VALUE hash)
02584 {
02585     static const char pat_source[] =
02586         "\\A\\s*(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?"
02587         "(z|[-+]\\d{2}(\\d{2})?)?)?\\s*\\z";
02588     static VALUE pat = Qnil;
02589 
02590     REGCOMP_I(pat);
02591     MATCH(str, pat, iso8601_bas_time_cb);
02592 }
02593 
02594 VALUE
02595 date__iso8601(VALUE str)
02596 {
02597     VALUE backref, hash;
02598 
02599     backref = rb_backref_get();
02600     rb_match_busy(backref);
02601 
02602     hash = rb_hash_new();
02603 
02604     if (iso8601_ext_datetime(str, hash))
02605         goto ok;
02606     if (iso8601_bas_datetime(str, hash))
02607         goto ok;
02608     if (iso8601_ext_time(str, hash))
02609         goto ok;
02610     if (iso8601_bas_time(str, hash))
02611         goto ok;
02612 
02613   ok:
02614     rb_backref_set(backref);
02615 
02616     return hash;
02617 }
02618 
02619 #undef SNUM
02620 #define SNUM 8
02621 
02622 static int
02623 rfc3339_cb(VALUE m, VALUE hash)
02624 {
02625     VALUE s[SNUM + 1];
02626 
02627     {
02628         int i;
02629         s[0] = Qnil;
02630         for (i = 1; i <= SNUM; i++)
02631             s[i] = rb_reg_nth_match(i, m);
02632     }
02633 
02634     set_hash("year", str2num(s[1]));
02635     set_hash("mon", str2num(s[2]));
02636     set_hash("mday", str2num(s[3]));
02637     set_hash("hour", str2num(s[4]));
02638     set_hash("min", str2num(s[5]));
02639     set_hash("sec", str2num(s[6]));
02640     set_hash("zone", s[8]);
02641     set_hash("offset", date_zone_to_diff(s[8]));
02642     if (!NIL_P(s[7]))
02643         set_hash("sec_fraction", sec_fraction(s[7]));
02644 
02645     return 1;
02646 }
02647 
02648 static int
02649 rfc3339(VALUE str, VALUE hash)
02650 {
02651     static const char pat_source[] =
02652         "\\A\\s*(-?\\d{4})-(\\d{2})-(\\d{2})"
02653         "(?:t|\\s)"
02654         "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?"
02655         "(z|[-+]\\d{2}:\\d{2})\\s*\\z";
02656     static VALUE pat = Qnil;
02657 
02658     REGCOMP_I(pat);
02659     MATCH(str, pat, rfc3339_cb);
02660 }
02661 
02662 VALUE
02663 date__rfc3339(VALUE str)
02664 {
02665     VALUE backref, hash;
02666 
02667     backref = rb_backref_get();
02668     rb_match_busy(backref);
02669 
02670     hash = rb_hash_new();
02671     rfc3339(str, hash);
02672     rb_backref_set(backref);
02673     return hash;
02674 }
02675 
02676 #undef SNUM
02677 #define SNUM 8
02678 
02679 static int
02680 xmlschema_datetime_cb(VALUE m, VALUE hash)
02681 {
02682     VALUE s[SNUM + 1];
02683 
02684     {
02685         int i;
02686         s[0] = Qnil;
02687         for (i = 1; i <= SNUM; i++)
02688             s[i] = rb_reg_nth_match(i, m);
02689     }
02690 
02691     set_hash("year", str2num(s[1]));
02692     if (!NIL_P(s[2]))
02693         set_hash("mon", str2num(s[2]));
02694     if (!NIL_P(s[3]))
02695         set_hash("mday", str2num(s[3]));
02696     if (!NIL_P(s[4]))
02697         set_hash("hour", str2num(s[4]));
02698     if (!NIL_P(s[5]))
02699         set_hash("min", str2num(s[5]));
02700     if (!NIL_P(s[6]))
02701         set_hash("sec", str2num(s[6]));
02702     if (!NIL_P(s[7]))
02703         set_hash("sec_fraction", sec_fraction(s[7]));
02704     if (!NIL_P(s[8])) {
02705         set_hash("zone", s[8]);
02706         set_hash("offset", date_zone_to_diff(s[8]));
02707     }
02708 
02709     return 1;
02710 }
02711 
02712 static int
02713 xmlschema_datetime(VALUE str, VALUE hash)
02714 {
02715     static const char pat_source[] =
02716         "\\A\\s*(-?\\d{4,})(?:-(\\d{2})(?:-(\\d{2}))?)?"
02717         "(?:t"
02718           "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?)?"
02719         "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
02720     static VALUE pat = Qnil;
02721 
02722     REGCOMP_I(pat);
02723     MATCH(str, pat, xmlschema_datetime_cb);
02724 }
02725 
02726 #undef SNUM
02727 #define SNUM 5
02728 
02729 static int
02730 xmlschema_time_cb(VALUE m, VALUE hash)
02731 {
02732     VALUE s[SNUM + 1];
02733 
02734     {
02735         int i;
02736         s[0] = Qnil;
02737         for (i = 1; i <= SNUM; i++)
02738             s[i] = rb_reg_nth_match(i, m);
02739     }
02740 
02741     set_hash("hour", str2num(s[1]));
02742     set_hash("min", str2num(s[2]));
02743     if (!NIL_P(s[3]))
02744         set_hash("sec", str2num(s[3]));
02745     if (!NIL_P(s[4]))
02746         set_hash("sec_fraction", sec_fraction(s[4]));
02747     if (!NIL_P(s[5])) {
02748         set_hash("zone", s[5]);
02749         set_hash("offset", date_zone_to_diff(s[5]));
02750     }
02751 
02752     return 1;
02753 }
02754 
02755 static int
02756 xmlschema_time(VALUE str, VALUE hash)
02757 {
02758     static const char pat_source[] =
02759         "\\A\\s*(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?"
02760         "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
02761     static VALUE pat = Qnil;
02762 
02763     REGCOMP_I(pat);
02764     MATCH(str, pat, xmlschema_time_cb);
02765 }
02766 
02767 #undef SNUM
02768 #define SNUM 4
02769 
02770 static int
02771 xmlschema_trunc_cb(VALUE m, VALUE hash)
02772 {
02773     VALUE s[SNUM + 1];
02774 
02775     {
02776         int i;
02777         s[0] = Qnil;
02778         for (i = 1; i <= SNUM; i++)
02779             s[i] = rb_reg_nth_match(i, m);
02780     }
02781 
02782     if (!NIL_P(s[1]))
02783         set_hash("mon", str2num(s[1]));
02784     if (!NIL_P(s[2]))
02785         set_hash("mday", str2num(s[2]));
02786     if (!NIL_P(s[3]))
02787         set_hash("mday", str2num(s[3]));
02788     if (!NIL_P(s[4])) {
02789         set_hash("zone", s[4]);
02790         set_hash("offset", date_zone_to_diff(s[4]));
02791     }
02792 
02793     return 1;
02794 }
02795 
02796 static int
02797 xmlschema_trunc(VALUE str, VALUE hash)
02798 {
02799     static const char pat_source[] =
02800         "\\A\\s*(?:--(\\d{2})(?:-(\\d{2}))?|---(\\d{2}))"
02801         "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
02802     static VALUE pat = Qnil;
02803 
02804     REGCOMP_I(pat);
02805     MATCH(str, pat, xmlschema_trunc_cb);
02806 }
02807 
02808 VALUE
02809 date__xmlschema(VALUE str)
02810 {
02811     VALUE backref, hash;
02812 
02813     backref = rb_backref_get();
02814     rb_match_busy(backref);
02815 
02816     hash = rb_hash_new();
02817 
02818     if (xmlschema_datetime(str, hash))
02819         goto ok;
02820     if (xmlschema_time(str, hash))
02821         goto ok;
02822     if (xmlschema_trunc(str, hash))
02823         goto ok;
02824 
02825   ok:
02826     rb_backref_set(backref);
02827 
02828     return hash;
02829 }
02830 
02831 #undef SNUM
02832 #define SNUM 8
02833 
02834 static int
02835 rfc2822_cb(VALUE m, VALUE hash)
02836 {
02837     VALUE s[SNUM + 1], y;
02838 
02839     {
02840         int i;
02841         s[0] = Qnil;
02842         for (i = 1; i <= SNUM; i++)
02843             s[i] = rb_reg_nth_match(i, m);
02844     }
02845 
02846     if (!NIL_P(s[1])) {
02847         set_hash("wday", INT2FIX(day_num(s[1])));
02848     }
02849     set_hash("mday", str2num(s[2]));
02850     set_hash("mon", INT2FIX(mon_num(s[3])));
02851     y = str2num(s[4]);
02852     if (RSTRING_LEN(s[4]) < 4)
02853         y = comp_year50(y);
02854     set_hash("year", y);
02855     set_hash("hour", str2num(s[5]));
02856     set_hash("min", str2num(s[6]));
02857     if (!NIL_P(s[7]))
02858         set_hash("sec", str2num(s[7]));
02859     set_hash("zone", s[8]);
02860     set_hash("offset", date_zone_to_diff(s[8]));
02861 
02862     return 1;
02863 }
02864 
02865 static int
02866 rfc2822(VALUE str, VALUE hash)
02867 {
02868     static const char pat_source[] =
02869         "\\A\\s*(?:(" ABBR_DAYS ")\\s*,\\s+)?"
02870         "(\\d{1,2})\\s+"
02871         "(" ABBR_MONTHS ")\\s+"
02872         "(-?\\d{2,})\\s+"
02873         "(\\d{2}):(\\d{2})(?::(\\d{2}))?\\s*"
02874         "([-+]\\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\\s*\\z";
02875     static VALUE pat = Qnil;
02876 
02877     REGCOMP_I(pat);
02878     MATCH(str, pat, rfc2822_cb);
02879 }
02880 
02881 VALUE
02882 date__rfc2822(VALUE str)
02883 {
02884     VALUE backref, hash;
02885 
02886     backref = rb_backref_get();
02887     rb_match_busy(backref);
02888 
02889     hash = rb_hash_new();
02890     rfc2822(str, hash);
02891     rb_backref_set(backref);
02892     return hash;
02893 }
02894 
02895 #undef SNUM
02896 #define SNUM 8
02897 
02898 static int
02899 httpdate_type1_cb(VALUE m, VALUE hash)
02900 {
02901     VALUE s[SNUM + 1];
02902 
02903     {
02904         int i;
02905         s[0] = Qnil;
02906         for (i = 1; i <= SNUM; i++)
02907             s[i] = rb_reg_nth_match(i, m);
02908     }
02909 
02910     set_hash("wday", INT2FIX(day_num(s[1])));
02911     set_hash("mday", str2num(s[2]));
02912     set_hash("mon", INT2FIX(mon_num(s[3])));
02913     set_hash("year", str2num(s[4]));
02914     set_hash("hour", str2num(s[5]));
02915     set_hash("min", str2num(s[6]));
02916     set_hash("sec", str2num(s[7]));
02917     set_hash("zone", s[8]);
02918     set_hash("offset", INT2FIX(0));
02919 
02920     return 1;
02921 }
02922 
02923 static int
02924 httpdate_type1(VALUE str, VALUE hash)
02925 {
02926     static const char pat_source[] =
02927         "\\A\\s*(" ABBR_DAYS ")\\s*,\\s+"
02928         "(\\d{2})\\s+"
02929         "(" ABBR_MONTHS ")\\s+"
02930         "(-?\\d{4})\\s+"
02931         "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
02932         "(gmt)\\s*\\z";
02933     static VALUE pat = Qnil;
02934 
02935     REGCOMP_I(pat);
02936     MATCH(str, pat, httpdate_type1_cb);
02937 }
02938 
02939 #undef SNUM
02940 #define SNUM 8
02941 
02942 static int
02943 httpdate_type2_cb(VALUE m, VALUE hash)
02944 {
02945     VALUE s[SNUM + 1], y;
02946 
02947     {
02948         int i;
02949         s[0] = Qnil;
02950         for (i = 1; i <= SNUM; i++)
02951             s[i] = rb_reg_nth_match(i, m);
02952     }
02953 
02954     set_hash("wday", INT2FIX(day_num(s[1])));
02955     set_hash("mday", str2num(s[2]));
02956     set_hash("mon", INT2FIX(mon_num(s[3])));
02957     y = str2num(s[4]);
02958     if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99)))
02959         y = comp_year69(y);
02960     set_hash("year", y);
02961     set_hash("hour", str2num(s[5]));
02962     set_hash("min", str2num(s[6]));
02963     set_hash("sec", str2num(s[7]));
02964     set_hash("zone", s[8]);
02965     set_hash("offset", INT2FIX(0));
02966 
02967     return 1;
02968 }
02969 
02970 static int
02971 httpdate_type2(VALUE str, VALUE hash)
02972 {
02973     static const char pat_source[] =
02974         "\\A\\s*(" DAYS ")\\s*,\\s+"
02975         "(\\d{2})\\s*-\\s*"
02976         "(" ABBR_MONTHS ")\\s*-\\s*"
02977         "(\\d{2})\\s+"
02978         "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
02979         "(gmt)\\s*\\z";
02980     static VALUE pat = Qnil;
02981 
02982     REGCOMP_I(pat);
02983     MATCH(str, pat, httpdate_type2_cb);
02984 }
02985 
02986 #undef SNUM
02987 #define SNUM 7
02988 
02989 static int
02990 httpdate_type3_cb(VALUE m, VALUE hash)
02991 {
02992     VALUE s[SNUM + 1];
02993 
02994     {
02995         int i;
02996         s[0] = Qnil;
02997         for (i = 1; i <= SNUM; i++)
02998             s[i] = rb_reg_nth_match(i, m);
02999     }
03000 
03001     set_hash("wday", INT2FIX(day_num(s[1])));
03002     set_hash("mon", INT2FIX(mon_num(s[2])));
03003     set_hash("mday", str2num(s[3]));
03004     set_hash("hour", str2num(s[4]));
03005     set_hash("min", str2num(s[5]));
03006     set_hash("sec", str2num(s[6]));
03007     set_hash("year", str2num(s[7]));
03008 
03009     return 1;
03010 }
03011 
03012 static int
03013 httpdate_type3(VALUE str, VALUE hash)
03014 {
03015     static const char pat_source[] =
03016         "\\A\\s*(" ABBR_DAYS ")\\s+"
03017         "(" ABBR_MONTHS ")\\s+"
03018         "(\\d{1,2})\\s+"
03019         "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
03020         "(\\d{4})\\s*\\z";
03021     static VALUE pat = Qnil;
03022 
03023     REGCOMP_I(pat);
03024     MATCH(str, pat, httpdate_type3_cb);
03025 }
03026 
03027 VALUE
03028 date__httpdate(VALUE str)
03029 {
03030     VALUE backref, hash;
03031 
03032     backref = rb_backref_get();
03033     rb_match_busy(backref);
03034 
03035     hash = rb_hash_new();
03036 
03037     if (httpdate_type1(str, hash))
03038         goto ok;
03039     if (httpdate_type2(str, hash))
03040         goto ok;
03041     if (httpdate_type3(str, hash))
03042         goto ok;
03043 
03044   ok:
03045     rb_backref_set(backref);
03046 
03047     return hash;
03048 }
03049 
03050 #undef SNUM
03051 #define SNUM 9
03052 
03053 static int
03054 jisx0301_cb(VALUE m, VALUE hash)
03055 {
03056     VALUE s[SNUM + 1];
03057     int ep;
03058 
03059     {
03060         int i;
03061         s[0] = Qnil;
03062         for (i = 1; i <= SNUM; i++)
03063             s[i] = rb_reg_nth_match(i, m);
03064     }
03065 
03066     ep = gengo(NIL_P(s[1]) ? 'h' : *RSTRING_PTR(s[1]));
03067     set_hash("year", f_add(str2num(s[2]), INT2FIX(ep)));
03068     set_hash("mon", str2num(s[3]));
03069     set_hash("mday", str2num(s[4]));
03070     if (!NIL_P(s[5])) {
03071         set_hash("hour", str2num(s[5]));
03072         if (!NIL_P(s[6]))
03073             set_hash("min", str2num(s[6]));
03074         if (!NIL_P(s[7]))
03075             set_hash("sec", str2num(s[7]));
03076     }
03077     if (!NIL_P(s[8]))
03078         set_hash("sec_fraction", sec_fraction(s[8]));
03079     if (!NIL_P(s[9])) {
03080         set_hash("zone", s[9]);
03081         set_hash("offset", date_zone_to_diff(s[9]));
03082     }
03083 
03084     return 1;
03085 }
03086 
03087 static int
03088 jisx0301(VALUE str, VALUE hash)
03089 {
03090     static const char pat_source[] =
03091         "\\A\\s*([mtsh])?(\\d{2})\\.(\\d{2})\\.(\\d{2})"
03092         "(?:t"
03093         "(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d*))?)?"
03094         "(z|[-+]\\d{2}(?::?\\d{2})?)?)?)?\\s*\\z";
03095     static VALUE pat = Qnil;
03096 
03097     REGCOMP_I(pat);
03098     MATCH(str, pat, jisx0301_cb);
03099 }
03100 
03101 VALUE
03102 date__jisx0301(VALUE str)
03103 {
03104     VALUE backref, hash;
03105 
03106     backref = rb_backref_get();
03107     rb_match_busy(backref);
03108 
03109     hash = rb_hash_new();
03110     if (jisx0301(str, hash))
03111         goto ok;
03112     hash = date__iso8601(str);
03113 
03114   ok:
03115     rb_backref_set(backref);
03116     return hash;
03117 }
03118 
03119 /*
03120 Local variables:
03121 c-file-style: "ruby"
03122 End:
03123 */
03124 
03125 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7