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