Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /* 00002 date_parse.c: Coded by Tadayoshi Funaba 2011,2012 00003 */ 00004 00005 #include "ruby.h" 00006 #include "ruby/encoding.h" 00007 #include "ruby/re.h" 00008 #include <ctype.h> 00009 00010 /* #define TIGHT_PARSER */ 00011 00012 #define sizeof_array(o) (sizeof o / sizeof o[0]) 00013 00014 #define f_negate(x) rb_funcall(x, rb_intern("-@"), 0) 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 /* us -> be */ 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 min = 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 "[[:alpha:].\\s]+(?:standard|daylight)\\stime\\b" 00769 "|" 00770 "[[: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)) /* pre */ 00828 goto ok; 00829 if (parse_era2(str, hash)) /* post */ 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; /* not found */ 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 set_hash("wday", INT2FIX(day_num(s[1]))); 02852 set_hash("mday", str2num(s[2])); 02853 set_hash("mon", INT2FIX(mon_num(s[3]))); 02854 y = str2num(s[4]); 02855 if (RSTRING_LEN(s[4]) < 4) 02856 y = comp_year50(y); 02857 set_hash("year", y); 02858 set_hash("hour", str2num(s[5])); 02859 set_hash("min", str2num(s[6])); 02860 if (!NIL_P(s[7])) 02861 set_hash("sec", str2num(s[7])); 02862 set_hash("zone", s[8]); 02863 set_hash("offset", date_zone_to_diff(s[8])); 02864 02865 return 1; 02866 } 02867 02868 static int 02869 rfc2822(VALUE str, VALUE hash) 02870 { 02871 static const char pat_source[] = 02872 "\\A\\s*(?:(" ABBR_DAYS ")\\s*,\\s+)?" 02873 "(\\d{1,2})\\s+" 02874 "(" ABBR_MONTHS ")\\s+" 02875 "(-?\\d{2,})\\s+" 02876 "(\\d{2}):(\\d{2})(?::(\\d{2}))?\\s*" 02877 "([-+]\\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\\s*\\z"; 02878 static VALUE pat = Qnil; 02879 02880 REGCOMP_I(pat); 02881 MATCH(str, pat, rfc2822_cb); 02882 } 02883 02884 VALUE 02885 date__rfc2822(VALUE str) 02886 { 02887 VALUE backref, hash; 02888 02889 backref = rb_backref_get(); 02890 rb_match_busy(backref); 02891 02892 hash = rb_hash_new(); 02893 rfc2822(str, hash); 02894 rb_backref_set(backref); 02895 return hash; 02896 } 02897 02898 #undef SNUM 02899 #define SNUM 8 02900 02901 static int 02902 httpdate_type1_cb(VALUE m, VALUE hash) 02903 { 02904 VALUE s[SNUM + 1]; 02905 02906 { 02907 int i; 02908 s[0] = Qnil; 02909 for (i = 1; i <= SNUM; i++) 02910 s[i] = rb_reg_nth_match(i, m); 02911 } 02912 02913 set_hash("wday", INT2FIX(day_num(s[1]))); 02914 set_hash("mday", str2num(s[2])); 02915 set_hash("mon", INT2FIX(mon_num(s[3]))); 02916 set_hash("year", str2num(s[4])); 02917 set_hash("hour", str2num(s[5])); 02918 set_hash("min", str2num(s[6])); 02919 set_hash("sec", str2num(s[7])); 02920 set_hash("zone", s[8]); 02921 set_hash("offset", INT2FIX(0)); 02922 02923 return 1; 02924 } 02925 02926 static int 02927 httpdate_type1(VALUE str, VALUE hash) 02928 { 02929 static const char pat_source[] = 02930 "\\A\\s*(" ABBR_DAYS ")\\s*,\\s+" 02931 "(\\d{2})\\s+" 02932 "(" ABBR_MONTHS ")\\s+" 02933 "(-?\\d{4})\\s+" 02934 "(\\d{2}):(\\d{2}):(\\d{2})\\s+" 02935 "(gmt)\\s*\\z"; 02936 static VALUE pat = Qnil; 02937 02938 REGCOMP_I(pat); 02939 MATCH(str, pat, httpdate_type1_cb); 02940 } 02941 02942 #undef SNUM 02943 #define SNUM 8 02944 02945 static int 02946 httpdate_type2_cb(VALUE m, VALUE hash) 02947 { 02948 VALUE s[SNUM + 1], y; 02949 02950 { 02951 int i; 02952 s[0] = Qnil; 02953 for (i = 1; i <= SNUM; i++) 02954 s[i] = rb_reg_nth_match(i, m); 02955 } 02956 02957 set_hash("wday", INT2FIX(day_num(s[1]))); 02958 set_hash("mday", str2num(s[2])); 02959 set_hash("mon", INT2FIX(mon_num(s[3]))); 02960 y = str2num(s[4]); 02961 if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) 02962 y = comp_year69(y); 02963 set_hash("year", y); 02964 set_hash("hour", str2num(s[5])); 02965 set_hash("min", str2num(s[6])); 02966 set_hash("sec", str2num(s[7])); 02967 set_hash("zone", s[8]); 02968 set_hash("offset", INT2FIX(0)); 02969 02970 return 1; 02971 } 02972 02973 static int 02974 httpdate_type2(VALUE str, VALUE hash) 02975 { 02976 static const char pat_source[] = 02977 "\\A\\s*(" DAYS ")\\s*,\\s+" 02978 "(\\d{2})\\s*-\\s*" 02979 "(" ABBR_MONTHS ")\\s*-\\s*" 02980 "(\\d{2})\\s+" 02981 "(\\d{2}):(\\d{2}):(\\d{2})\\s+" 02982 "(gmt)\\s*\\z"; 02983 static VALUE pat = Qnil; 02984 02985 REGCOMP_I(pat); 02986 MATCH(str, pat, httpdate_type2_cb); 02987 } 02988 02989 #undef SNUM 02990 #define SNUM 7 02991 02992 static int 02993 httpdate_type3_cb(VALUE m, VALUE hash) 02994 { 02995 VALUE s[SNUM + 1]; 02996 02997 { 02998 int i; 02999 s[0] = Qnil; 03000 for (i = 1; i <= SNUM; i++) 03001 s[i] = rb_reg_nth_match(i, m); 03002 } 03003 03004 set_hash("wday", INT2FIX(day_num(s[1]))); 03005 set_hash("mon", INT2FIX(mon_num(s[2]))); 03006 set_hash("mday", str2num(s[3])); 03007 set_hash("hour", str2num(s[4])); 03008 set_hash("min", str2num(s[5])); 03009 set_hash("sec", str2num(s[6])); 03010 set_hash("year", str2num(s[7])); 03011 03012 return 1; 03013 } 03014 03015 static int 03016 httpdate_type3(VALUE str, VALUE hash) 03017 { 03018 static const char pat_source[] = 03019 "\\A\\s*(" ABBR_DAYS ")\\s+" 03020 "(" ABBR_MONTHS ")\\s+" 03021 "(\\d{1,2})\\s+" 03022 "(\\d{2}):(\\d{2}):(\\d{2})\\s+" 03023 "(\\d{4})\\s*\\z"; 03024 static VALUE pat = Qnil; 03025 03026 REGCOMP_I(pat); 03027 MATCH(str, pat, httpdate_type3_cb); 03028 } 03029 03030 VALUE 03031 date__httpdate(VALUE str) 03032 { 03033 VALUE backref, hash; 03034 03035 backref = rb_backref_get(); 03036 rb_match_busy(backref); 03037 03038 hash = rb_hash_new(); 03039 03040 if (httpdate_type1(str, hash)) 03041 goto ok; 03042 if (httpdate_type2(str, hash)) 03043 goto ok; 03044 if (httpdate_type3(str, hash)) 03045 goto ok; 03046 03047 ok: 03048 rb_backref_set(backref); 03049 03050 return hash; 03051 } 03052 03053 #undef SNUM 03054 #define SNUM 9 03055 03056 static int 03057 jisx0301_cb(VALUE m, VALUE hash) 03058 { 03059 VALUE s[SNUM + 1]; 03060 int ep; 03061 03062 { 03063 int i; 03064 s[0] = Qnil; 03065 for (i = 1; i <= SNUM; i++) 03066 s[i] = rb_reg_nth_match(i, m); 03067 } 03068 03069 ep = gengo(NIL_P(s[1]) ? 'h' : *RSTRING_PTR(s[1])); 03070 set_hash("year", f_add(str2num(s[2]), INT2FIX(ep))); 03071 set_hash("mon", str2num(s[3])); 03072 set_hash("mday", str2num(s[4])); 03073 if (!NIL_P(s[5])) { 03074 set_hash("hour", str2num(s[5])); 03075 if (!NIL_P(s[6])) 03076 set_hash("min", str2num(s[6])); 03077 if (!NIL_P(s[7])) 03078 set_hash("sec", str2num(s[7])); 03079 } 03080 if (!NIL_P(s[8])) 03081 set_hash("sec_fraction", sec_fraction(s[8])); 03082 if (!NIL_P(s[9])) { 03083 set_hash("zone", s[9]); 03084 set_hash("offset", date_zone_to_diff(s[9])); 03085 } 03086 03087 return 1; 03088 } 03089 03090 static int 03091 jisx0301(VALUE str, VALUE hash) 03092 { 03093 static const char pat_source[] = 03094 "\\A\\s*([mtsh])?(\\d{2})\\.(\\d{2})\\.(\\d{2})" 03095 "(?:t" 03096 "(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d*))?)?" 03097 "(z|[-+]\\d{2}(?::?\\d{2})?)?)?)?\\s*\\z"; 03098 static VALUE pat = Qnil; 03099 03100 REGCOMP_I(pat); 03101 MATCH(str, pat, jisx0301_cb); 03102 } 03103 03104 VALUE 03105 date__jisx0301(VALUE str) 03106 { 03107 VALUE backref, hash; 03108 03109 backref = rb_backref_get(); 03110 rb_match_busy(backref); 03111 03112 hash = rb_hash_new(); 03113 if (jisx0301(str, hash)) 03114 goto ok; 03115 hash = date__iso8601(str); 03116 03117 ok: 03118 rb_backref_set(backref); 03119 return hash; 03120 } 03121 03122 /* 03123 Local variables: 03124 c-file-style: "ruby" 03125 End: 03126 */ 03127