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)
#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
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))
00823 goto ok;
00824 if (parse_era2(str, hash))
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;
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
03121
03122
03123
03124
03125