From fcbf63e62c627deae76c1b8cb8c0876c536ed811 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 16 Mar 2020 18:49:26 +0900 Subject: Fresh start --- jni/ruby/ext/date/date_parse.c | 3128 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3128 insertions(+) create mode 100644 jni/ruby/ext/date/date_parse.c (limited to 'jni/ruby/ext/date/date_parse.c') diff --git a/jni/ruby/ext/date/date_parse.c b/jni/ruby/ext/date/date_parse.c new file mode 100644 index 0000000..239e264 --- /dev/null +++ b/jni/ruby/ext/date/date_parse.c @@ -0,0 +1,3128 @@ +/* + date_parse.c: Coded by Tadayoshi Funaba 2011,2012 +*/ + +#include "ruby.h" +#include "ruby/encoding.h" +#include "ruby/re.h" +#include + +/* #define TIGHT_PARSER */ + +#define sizeof_array(o) (sizeof o / sizeof o[0]) + +#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) +#define f_mod(x,y) rb_funcall(x, '%', 1, y) +#define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y) + +#define f_lt_p(x,y) rb_funcall(x, '<', 1, y) +#define f_gt_p(x,y) rb_funcall(x, '>', 1, y) +#define f_le_p(x,y) rb_funcall(x, rb_intern("<="), 1, y) +#define f_ge_p(x,y) rb_funcall(x, rb_intern(">="), 1, y) + +#define f_to_s(x) rb_funcall(x, rb_intern("to_s"), 0) + +#define f_match(r,s) rb_funcall(r, rb_intern("match"), 1, s) +#define f_aref(o,i) rb_funcall(o, rb_intern("[]"), 1, i) +#define f_aref2(o,i,j) rb_funcall(o, rb_intern("[]"), 2, i, j) +#define f_begin(o,i) rb_funcall(o, rb_intern("begin"), 1, i) +#define f_end(o,i) rb_funcall(o, rb_intern("end"), 1, i) +#define f_aset(o,i,v) rb_funcall(o, rb_intern("[]="), 2, i, v) +#define f_aset2(o,i,j,v) rb_funcall(o, rb_intern("[]="), 3, i, j, v) +#define f_sub_bang(s,r,x) rb_funcall(s, rb_intern("sub!"), 2, r, x) +#define f_gsub_bang(s,r,x) rb_funcall(s, rb_intern("gsub!"), 2, r, x) + +#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v) +#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k))) +#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k))) + +#define cstr2num(s) rb_cstr_to_inum(s, 10, 0) +#define str2num(s) rb_str_to_inum(s, 10, 0) + +static const char *abbr_days[] = { + "sun", "mon", "tue", "wed", + "thu", "fri", "sat" +}; + +static const char *abbr_months[] = { + "jan", "feb", "mar", "apr", "may", "jun", + "jul", "aug", "sep", "oct", "nov", "dec" +}; + +#define issign(c) ((c) == '-' || (c) == '+') +#define asp_string() rb_str_new(" ", 1) +#ifdef TIGHT_PARSER +#define asuba_string() rb_str_new("\001", 1) +#define asubb_string() rb_str_new("\002", 1) +#define asubw_string() rb_str_new("\027", 1) +#define asubt_string() rb_str_new("\024", 1) +#endif + +#define DECDIGIT "0123456789" + +static void +s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) +{ + VALUE c = Qnil; + + if (!RB_TYPE_P(m, T_STRING)) + m = f_to_s(m); + + if (!NIL_P(y) && !NIL_P(m) && NIL_P(d)) { + VALUE oy = y; + VALUE om = m; + VALUE od = d; + + y = od; + m = oy; + d = om; + } + + if (NIL_P(y)) { + if (!NIL_P(d) && RSTRING_LEN(d) > 2) { + y = d; + d = Qnil; + } + if (!NIL_P(d) && *RSTRING_PTR(d) == '\'') { + y = d; + d = Qnil; + } + } + + if (!NIL_P(y)) { + const char *s, *bp, *ep; + size_t l; + + s = RSTRING_PTR(y); + while (!issign((unsigned char)*s) && !isdigit((unsigned char)*s)) + s++; + bp = s; + if (issign((unsigned char)*s)) + s++; + l = strspn(s, DECDIGIT); + ep = s + l; + if (*ep) { + y = d; + d = rb_str_new(bp, ep - bp); + } + } + + if (!NIL_P(m)) { + const char *s; + + s = RSTRING_PTR(m); + if (*s == '\'' || RSTRING_LEN(m) > 2) { + /* us -> be */ + VALUE oy = y; + VALUE om = m; + VALUE od = d; + + y = om; + m = od; + d = oy; + } + } + + if (!NIL_P(d)) { + const char *s; + + s = RSTRING_PTR(d); + if (*s == '\'' || RSTRING_LEN(d) > 2) { + VALUE oy = y; + VALUE od = d; + + y = od; + d = oy; + } + } + + if (!NIL_P(y)) { + const char *s, *bp, *ep; + int sign = 0; + size_t l; + VALUE iy; + + s = RSTRING_PTR(y); + while (!issign((unsigned char)*s) && !isdigit((unsigned char)*s)) + s++; + bp = s; + if (issign(*s)) { + s++; + sign = 1; + } + if (sign) + c = Qfalse; + l = strspn(s, DECDIGIT); + ep = s + l; + if (l > 2) + c = Qfalse; + { + char *buf; + + buf = ALLOCA_N(char, ep - bp + 1); + memcpy(buf, bp, ep - bp); + buf[ep - bp] = '\0'; + iy = cstr2num(buf); + } + set_hash("year", iy); + } + + if (bc) + set_hash("_bc", Qtrue); + + if (!NIL_P(m)) { + const char *s, *bp, *ep; + size_t l; + VALUE im; + + s = RSTRING_PTR(m); + while (!isdigit((unsigned char)*s)) + s++; + bp = s; + l = strspn(s, DECDIGIT); + ep = s + l; + { + char *buf; + + buf = ALLOCA_N(char, ep - bp + 1); + memcpy(buf, bp, ep - bp); + buf[ep - bp] = '\0'; + im = cstr2num(buf); + } + set_hash("mon", im); + } + + if (!NIL_P(d)) { + const char *s, *bp, *ep; + size_t l; + VALUE id; + + s = RSTRING_PTR(d); + while (!isdigit((unsigned char)*s)) + s++; + bp = s; + l = strspn(s, DECDIGIT); + ep = s + l; + { + char *buf; + + buf = ALLOCA_N(char, ep - bp + 1); + memcpy(buf, bp, ep - bp); + buf[ep - bp] = '\0'; + id = cstr2num(buf); + } + set_hash("mday", id); + } + + if (!NIL_P(c)) + set_hash("_comp", c); +} + +#define DAYS "sunday|monday|tuesday|wednesday|thursday|friday|saturday" +#define MONTHS "january|february|march|april|may|june|july|august|september|october|november|december" +#define ABBR_DAYS "sun|mon|tue|wed|thu|fri|sat" +#define ABBR_MONTHS "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec" + +#ifdef TIGHT_PARSER +#define VALID_DAYS "(?:" DAYS ")" "|(?:tues|wednes|thurs|thur|" ABBR_DAYS ")\\.?" +#define VALID_MONTHS "(?:" MONTHS ")" "|(?:sept|" ABBR_MONTHS ")\\.?" +#define DOTLESS_VALID_MONTHS "(?:" MONTHS ")" "|(?:sept|" ABBR_MONTHS ")" +#define BOS "\\A\\s*" +#define FPA "\\001" +#define FPB "\\002" +#define FPW "\\027" +#define FPT "\\024" +#define FPW_COM "\\s*(?:" FPW "\\s*,?)?\\s*" +#define FPT_COM "\\s*(?:" FPT "\\s*,?)?\\s*" +#define COM_FPW "\\s*(?:,?\\s*" FPW ")?\\s*" +#define COM_FPT "\\s*(?:,?\\s*(?:@|\\b[aA][tT]\\b)?\\s*" FPT ")?\\s*" +#define TEE_FPT "\\s*(?:[tT]?" FPT ")?" +#define EOS "\\s*\\z" +#endif + +static VALUE +regcomp(const char *source, long len, int opt) +{ + VALUE pat; + + pat = rb_reg_new(source, len, opt); + rb_gc_register_mark_object(pat); + return pat; +} + +#define REGCOMP(pat,opt) \ +{ \ + if (NIL_P(pat)) \ + pat = regcomp(pat##_source, sizeof pat##_source - 1, opt); \ +} + +#define REGCOMP_0(pat) REGCOMP(pat, 0) +#define REGCOMP_I(pat) REGCOMP(pat, ONIG_OPTION_IGNORECASE) + +#define MATCH(s,p,c) \ +{ \ + return match(s, p, hash, c); \ +} + +static int +match(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE)) +{ + VALUE m; + + m = f_match(pat, str); + + if (NIL_P(m)) + return 0; + + (*cb)(m, hash); + + return 1; +} + +static int +subx(VALUE str, VALUE rep, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE)) +{ + VALUE m; + + m = f_match(pat, str); + + if (NIL_P(m)) + return 0; + + { + VALUE be, en; + + be = f_begin(m, INT2FIX(0)); + en = f_end(m, INT2FIX(0)); + f_aset2(str, be, LONG2NUM(NUM2LONG(en) - NUM2LONG(be)), rep); + (*cb)(m, hash); + } + + return 1; +} + +#define SUBS(s,p,c) \ +{ \ + return subx(s, asp_string(), p, hash, c); \ +} + +#ifdef TIGHT_PARSER +#define SUBA(s,p,c) \ +{ \ + return subx(s, asuba_string(), p, hash, c); \ +} + +#define SUBB(s,p,c) \ +{ \ + return subx(s, asubb_string(), p, hash, c); \ +} + +#define SUBW(s,p,c) \ +{ \ + return subx(s, asubw_string(), p, hash, c); \ +} + +#define SUBT(s,p,c) \ +{ \ + return subx(s, asubt_string(), p, hash, c); \ +} +#endif + +struct zone { + const char *name; + int offset; +}; + +static struct zone zones_source[] = { + {"ut", 0*3600}, {"gmt", 0*3600}, {"est", -5*3600}, {"edt", -4*3600}, + {"cst", -6*3600}, {"cdt", -5*3600}, {"mst", -7*3600}, {"mdt", -6*3600}, + {"pst", -8*3600}, {"pdt", -7*3600}, + {"a", 1*3600}, {"b", 2*3600}, {"c", 3*3600}, {"d", 4*3600}, + {"e", 5*3600}, {"f", 6*3600}, {"g", 7*3600}, {"h", 8*3600}, + {"i", 9*3600}, {"k", 10*3600}, {"l", 11*3600}, {"m", 12*3600}, + {"n", -1*3600}, {"o", -2*3600}, {"p", -3*3600}, {"q", -4*3600}, + {"r", -5*3600}, {"s", -6*3600}, {"t", -7*3600}, {"u", -8*3600}, + {"v", -9*3600}, {"w", -10*3600}, {"x", -11*3600}, {"y", -12*3600}, + {"z", 0*3600}, + + {"utc", 0*3600}, {"wet", 0*3600}, + {"at", -2*3600}, {"brst",-2*3600}, {"ndt", -(2*3600+1800)}, + {"art", -3*3600}, {"adt", -3*3600}, {"brt", -3*3600}, {"clst",-3*3600}, + {"nst", -(3*3600+1800)}, + {"ast", -4*3600}, {"clt", -4*3600}, + {"akdt",-8*3600}, {"ydt", -8*3600}, + {"akst",-9*3600}, {"hadt",-9*3600}, {"hdt", -9*3600}, {"yst", -9*3600}, + {"ahst",-10*3600},{"cat",-10*3600}, {"hast",-10*3600},{"hst",-10*3600}, + {"nt", -11*3600}, + {"idlw",-12*3600}, + {"bst", 1*3600}, {"cet", 1*3600}, {"fwt", 1*3600}, {"met", 1*3600}, + {"mewt", 1*3600}, {"mez", 1*3600}, {"swt", 1*3600}, {"wat", 1*3600}, + {"west", 1*3600}, + {"cest", 2*3600}, {"eet", 2*3600}, {"fst", 2*3600}, {"mest", 2*3600}, + {"mesz", 2*3600}, {"sast", 2*3600}, {"sst", 2*3600}, + {"bt", 3*3600}, {"eat", 3*3600}, {"eest", 3*3600}, {"msk", 3*3600}, + {"msd", 4*3600}, {"zp4", 4*3600}, + {"zp5", 5*3600}, {"ist", (5*3600+1800)}, + {"zp6", 6*3600}, + {"wast", 7*3600}, + {"cct", 8*3600}, {"sgt", 8*3600}, {"wadt", 8*3600}, + {"jst", 9*3600}, {"kst", 9*3600}, + {"east",10*3600}, {"gst", 10*3600}, + {"eadt",11*3600}, + {"idle",12*3600}, {"nzst",12*3600}, {"nzt", 12*3600}, + {"nzdt",13*3600}, + + {"afghanistan", 16200}, {"alaskan", -32400}, + {"arab", 10800}, {"arabian", 14400}, + {"arabic", 10800}, {"atlantic", -14400}, + {"aus central", 34200}, {"aus eastern", 36000}, + {"azores", -3600}, {"canada central", -21600}, + {"cape verde", -3600}, {"caucasus", 14400}, + {"cen. australia", 34200}, {"central america", -21600}, + {"central asia", 21600}, {"central europe", 3600}, + {"central european", 3600}, {"central pacific", 39600}, + {"central", -21600}, {"china", 28800}, + {"dateline", -43200}, {"e. africa", 10800}, + {"e. australia", 36000}, {"e. europe", 7200}, + {"e. south america", -10800}, {"eastern", -18000}, + {"egypt", 7200}, {"ekaterinburg", 18000}, + {"fiji", 43200}, {"fle", 7200}, + {"greenland", -10800}, {"greenwich", 0}, + {"gtb", 7200}, {"hawaiian", -36000}, + {"india", 19800}, {"iran", 12600}, + {"jerusalem", 7200}, {"korea", 32400}, + {"mexico", -21600}, {"mid-atlantic", -7200}, + {"mountain", -25200}, {"myanmar", 23400}, + {"n. central asia", 21600}, {"nepal", 20700}, + {"new zealand", 43200}, {"newfoundland", -12600}, + {"north asia east", 28800}, {"north asia", 25200}, + {"pacific sa", -14400}, {"pacific", -28800}, + {"romance", 3600}, {"russian", 10800}, + {"sa eastern", -10800}, {"sa pacific", -18000}, + {"sa western", -14400}, {"samoa", -39600}, + {"se asia", 25200}, {"malay peninsula", 28800}, + {"south africa", 7200}, {"sri lanka", 21600}, + {"taipei", 28800}, {"tasmania", 36000}, + {"tokyo", 32400}, {"tonga", 46800}, + {"us eastern", -18000}, {"us mountain", -25200}, + {"vladivostok", 36000}, {"w. australia", 28800}, + {"w. central africa", 3600}, {"w. europe", 3600}, + {"west asia", 18000}, {"west pacific", 36000}, + {"yakutsk", 32400} +}; + +VALUE +date_zone_to_diff(VALUE str) +{ + VALUE offset = Qnil; + + long l, i; + char *s, *dest, *d; + int sp = 1; + + l = RSTRING_LEN(str); + s = RSTRING_PTR(str); + + dest = d = ALLOCA_N(char, l + 1); + + for (i = 0; i < l; i++) { + if (isspace((unsigned char)s[i]) || s[i] == '\0') { + if (!sp) + *d++ = ' '; + sp = 1; + } + else { + if (isalpha((unsigned char)s[i])) + *d++ = tolower((unsigned char)s[i]); + else + *d++ = s[i]; + sp = 0; + } + } + if (d > dest) { + if (*(d - 1) == ' ') + --d; + *d = '\0'; + } + str = rb_str_new2(dest); + { +#define STD " standard time" +#define DST " daylight time" + char *ss, *ds; + long sl, dl; + int dst = 0; + + sl = RSTRING_LEN(str) - (sizeof STD - 1); + ss = RSTRING_PTR(str) + sl; + dl = RSTRING_LEN(str) - (sizeof DST - 1); + ds = RSTRING_PTR(str) + dl; + + if (sl >= 0 && strcmp(ss, STD) == 0) { + str = rb_str_new(RSTRING_PTR(str), sl); + } + else if (dl >= 0 && strcmp(ds, DST) == 0) { + str = rb_str_new(RSTRING_PTR(str), dl); + dst = 1; + } +#undef STD +#undef DST + else { +#define DST " dst" + char *ds; + long dl; + + dl = RSTRING_LEN(str) - (sizeof DST - 1); + ds = RSTRING_PTR(str) + dl; + + if (dl >= 0 && strcmp(ds, DST) == 0) { + str = rb_str_new(RSTRING_PTR(str), dl); + dst = 1; + } +#undef DST + } + { + static VALUE zones = Qnil; + + if (NIL_P(zones)) { + int i; + + zones = rb_hash_new(); + rb_gc_register_mark_object(zones); + for (i = 0; i < (int)sizeof_array(zones_source); i++) { + VALUE name = rb_str_new2(zones_source[i].name); + VALUE offset = INT2FIX(zones_source[i].offset); + rb_hash_aset(zones, name, offset); + } + } + + offset = f_aref(zones, str); + if (!NIL_P(offset)) { + if (dst) + offset = f_add(offset, INT2FIX(3600)); + goto ok; + } + } + { + char *s, *p; + VALUE sign; + VALUE hour = Qnil, min = Qnil, sec = Qnil; + VALUE str_orig; + + s = RSTRING_PTR(str); + str_orig = str; + + if (strncmp(s, "gmt", 3) == 0 || + strncmp(s, "utc", 3) == 0) + s += 3; + if (issign(*s)) { + sign = rb_str_new(s, 1); + s++; + + str = rb_str_new2(s); + + if (p = strchr(s, ':')) { + hour = rb_str_new(s, p - s); + s = ++p; + if (p = strchr(s, ':')) { + min = rb_str_new(s, p - s); + s = ++p; + if (p = strchr(s, ':')) { + sec = rb_str_new(s, p - s); + } + else + sec = rb_str_new2(s); + } + else + min = rb_str_new2(s); + RB_GC_GUARD(str_orig); + goto num; + } + if (strpbrk(RSTRING_PTR(str), ",.")) { + char *a, *b; + + a = ALLOCA_N(char, RSTRING_LEN(str) + 1); + strcpy(a, RSTRING_PTR(str)); + b = strpbrk(a, ",."); + *b = '\0'; + b++; + + hour = cstr2num(a); + min = f_mul(rb_rational_new2 + (cstr2num(b), + f_expt(INT2FIX(10), + LONG2NUM((long)strlen(b)))), + INT2FIX(60)); + goto num; + } + { + const char *cs = RSTRING_PTR(str); + long cl = RSTRING_LEN(str); + + if (cl % 2) { + if (cl >= 1) + hour = rb_str_new(&cs[0], 1); + if (cl >= 3) + min = rb_str_new(&cs[1], 2); + if (cl >= 5) + sec = rb_str_new(&cs[3], 2); + } + else { + if (cl >= 2) + hour = rb_str_new(&cs[0], 2); + if (cl >= 4) + min = rb_str_new(&cs[2], 2); + if (cl >= 6) + sec = rb_str_new(&cs[4], 2); + } + goto num; + } + num: + if (NIL_P(hour)) + offset = INT2FIX(0); + else { + if (RB_TYPE_P(hour, T_STRING)) + hour = str2num(hour); + offset = f_mul(hour, INT2FIX(3600)); + } + if (!NIL_P(min)) { + if (RB_TYPE_P(min, T_STRING)) + min = str2num(min); + offset = f_add(offset, f_mul(min, INT2FIX(60))); + } + if (!NIL_P(sec)) + offset = f_add(offset, str2num(sec)); + if (!NIL_P(sign) && + RSTRING_LEN(sign) == 1 && + *RSTRING_PTR(sign) == '-') + offset = f_negate(offset); + } + } + } + RB_GC_GUARD(str); + ok: + return offset; +} + +static int +day_num(VALUE s) +{ + int i; + + for (i = 0; i < (int)sizeof_array(abbr_days); i++) + if (strncasecmp(abbr_days[i], RSTRING_PTR(s), 3) == 0) + break; + return i; +} + +static int +mon_num(VALUE s) +{ + int i; + + for (i = 0; i < (int)sizeof_array(abbr_months); i++) + if (strncasecmp(abbr_months[i], RSTRING_PTR(s), 3) == 0) + break; + return i + 1; +} + +static int +parse_day_cb(VALUE m, VALUE hash) +{ + VALUE s; + + s = rb_reg_nth_match(1, m); + set_hash("wday", INT2FIX(day_num(s))); + return 1; +} + +static int +parse_day(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b(" ABBR_DAYS ")[^-/\\d\\s]*" +#else + "(" VALID_DAYS ")" +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); +#ifndef TIGHT_PARSER + SUBS(str, pat, parse_day_cb); +#else + SUBW(str, pat, parse_day_cb); +#endif +} + +static int +parse_time2_cb(VALUE m, VALUE hash) +{ + VALUE h, min, s, f, p; + + h = rb_reg_nth_match(1, m); + h = str2num(h); + + min = rb_reg_nth_match(2, m); + if (!NIL_P(min)) + min = str2num(min); + + s = rb_reg_nth_match(3, m); + if (!NIL_P(s)) + s = str2num(s); + + f = rb_reg_nth_match(4, m); + + if (!NIL_P(f)) + f = rb_rational_new2(str2num(f), + f_expt(INT2FIX(10), LONG2NUM(RSTRING_LEN(f)))); + + p = rb_reg_nth_match(5, m); + + if (!NIL_P(p)) { + int ih = NUM2INT(h); + ih %= 12; + if (*RSTRING_PTR(p) == 'P' || *RSTRING_PTR(p) == 'p') + ih += 12; + h = INT2FIX(ih); + } + + set_hash("hour", h); + if (!NIL_P(min)) + set_hash("min", min); + if (!NIL_P(s)) + set_hash("sec", s); + if (!NIL_P(f)) + set_hash("sec_fraction", f); + + return 1; +} + +static int +parse_time_cb(VALUE m, VALUE hash) +{ + static const char pat_source[] = + "\\A(\\d+)h?" + "(?:\\s*:?\\s*(\\d+)m?" + "(?:" + "\\s*:?\\s*(\\d+)(?:[,.](\\d+))?s?" + ")?" + ")?" + "(?:\\s*([ap])(?:m\\b|\\.m\\.))?"; + static VALUE pat = Qnil; + VALUE s1, s2; + + s1 = rb_reg_nth_match(1, m); + s2 = rb_reg_nth_match(2, m); + + if (!NIL_P(s2)) + set_hash("zone", s2); + + REGCOMP_I(pat); + + { + VALUE m = f_match(pat, s1); + + if (NIL_P(m)) + return 0; + parse_time2_cb(m, hash); + } + + return 1; +} + +static int +parse_time(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "(" + "(?:" + "\\d+\\s*:\\s*\\d+" + "(?:" +#ifndef TIGHT_PARSER + "\\s*:\\s*\\d+(?:[,.]\\d*)?" +#else + "\\s*:\\s*\\d+(?:[,.]\\d+)?" +#endif + ")?" + "|" + "\\d+\\s*h(?:\\s*\\d+m?(?:\\s*\\d+s?)?)?" + ")" + "(?:" + "\\s*" + "[ap](?:m\\b|\\.m\\.)" + ")?" + "|" + "\\d+\\s*[ap](?:m\\b|\\.m\\.)" + ")" + "(?:" + "\\s*" + "(" + "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?" + "|" + "(?-i:[[:alpha:].\\s]+)(?:standard|daylight)\\stime\\b" + "|" + "(?-i:[[:alpha:]]+)(?:\\sdst)?\\b" + ")" + ")?"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); +#ifndef TIGHT_PARSER + SUBS(str, pat, parse_time_cb); +#else + SUBT(str, pat, parse_time_cb); +#endif +} + +#ifdef TIGHT_PARSER +static int +parse_era1_cb(VALUE m, VALUE hash) +{ + return 1; +} + +static int +parse_era1(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "(a(?:d|\\.d\\.))"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBA(str, pat, parse_era1_cb); +} + +static int +parse_era2_cb(VALUE m, VALUE hash) +{ + VALUE b; + + b = rb_reg_nth_match(1, m); + if (*RSTRING_PTR(b) == 'B' || + *RSTRING_PTR(b) == 'b') + set_hash("_bc", Qtrue); + return 1; +} + +static int +parse_era2(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|b(?:c|\\.c\\.))"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBB(str, pat, parse_era2_cb); +} + +static int +parse_era(VALUE str, VALUE hash) +{ + if (parse_era1(str, hash)) /* pre */ + goto ok; + if (parse_era2(str, hash)) /* post */ + goto ok; + return 0; + ok: + return 1; +} +#endif + +#ifdef TIGHT_PARSER +static int +check_year_width(VALUE y) +{ + char *s; + size_t l; + + s = RSTRING_PTR(y); + l = strcspn(s, DECDIGIT); + s += l; + l = strspn(s, DECDIGIT); + if (l != 2) + return 0; + return 1; +} + +static int +check_apost(VALUE a, VALUE b, VALUE c) +{ + int f = 0; + + if (!NIL_P(a) && *RSTRING_PTR(a) == '\'') { + if (!check_year_width(a)) + return 0; + f++; + } + if (!NIL_P(b) && *RSTRING_PTR(b) == '\'') { + if (!check_year_width(b)) + return 0; + if (!NIL_P(c)) + return 0; + f++; + } + if (!NIL_P(c) && *RSTRING_PTR(c) == '\'') { + if (!check_year_width(c)) + return 0; + f++; + } + if (f > 1) + return 0; + return 1; +} +#endif + +static int +parse_eu_cb(VALUE m, VALUE hash) +{ +#ifndef TIGHT_PARSER + VALUE y, mon, d, b; + + d = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + b = rb_reg_nth_match(3, m); + y = rb_reg_nth_match(4, m); + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, !NIL_P(b) && + (*RSTRING_PTR(b) == 'B' || + *RSTRING_PTR(b) == 'b')); +#else + VALUE y, mon, d; + + d = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(d, mon, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); +#endif + return 1; +} + +static int +parse_eu(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifdef TIGHT_PARSER + BOS + FPW_COM FPT_COM +#endif +#ifndef TIGHT_PARSER + "('?\\d+)[^-\\d\\s]*" +#else + "(\\d+)(?:(?:st|nd|rd|th)\\b)?" +#endif + "\\s*" +#ifndef TIGHT_PARSER + "(" ABBR_MONTHS ")[^-\\d\\s']*" +#else + "(" VALID_MONTHS ")" +#endif + "(?:" + "\\s*" +#ifndef TIGHT_PARSER + "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?" + "\\s*" + "('?-?\\d+(?:(?:st|nd|rd|th)\\b)?)" +#else + "(?:" FPA ")?" + "\\s*" + "([-']?\\d+)" + "\\s*" + "(?:" FPA "|" FPB ")?" +#endif + ")?" +#ifdef TIGHT_PARSER + COM_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_eu_cb); +} + +static int +parse_us_cb(VALUE m, VALUE hash) +{ +#ifndef TIGHT_PARSER + VALUE y, mon, d, b; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + + b = rb_reg_nth_match(3, m); + y = rb_reg_nth_match(4, m); + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, !NIL_P(b) && + (*RSTRING_PTR(b) == 'B' || + *RSTRING_PTR(b) == 'b')); +#else + VALUE y, mon, d; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(mon, d, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); +#endif + return 1; +} + +static int +parse_us(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifdef TIGHT_PARSER + BOS + FPW_COM FPT_COM +#endif +#ifndef TIGHT_PARSER + "\\b(" ABBR_MONTHS ")[^-\\d\\s']*" +#else + "\\b(" VALID_MONTHS ")" +#endif + "\\s*" +#ifndef TIGHT_PARSER + "('?\\d+)[^-\\d\\s']*" +#else + "('?\\d+)(?:(?:st|nd|rd|th)\\b)?" + COM_FPT +#endif + "(?:" + "\\s*,?" + "\\s*" +#ifndef TIGHT_PARSER + "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?" + "\\s*" + "('?-?\\d+)" +#else + "(?:" FPA ")?" + "\\s*" + "([-']?\\d+)" + "\\s*" + "(?:" FPA "|" FPB ")?" +#endif + ")?" +#ifdef TIGHT_PARSER + COM_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_us_cb); +} + +static int +parse_iso_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + y = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + d = rb_reg_nth_match(3, m); + +#ifdef TIGHT_PARSER + if (!check_apost(y, mon, d)) + return 0; +#endif + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_iso(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "('?[-+]?\\d+)-(\\d+)-('?-?\\d+)" +#else + BOS + FPW_COM FPT_COM + "([-+']?\\d+)-(\\d+)-([-']?\\d+)" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_iso_cb); +} + +static int +parse_iso21_cb(VALUE m, VALUE hash) +{ + VALUE y, w, d; + + y = rb_reg_nth_match(1, m); + w = rb_reg_nth_match(2, m); + d = rb_reg_nth_match(3, m); + + if (!NIL_P(y)) + set_hash("cwyear", str2num(y)); + set_hash("cweek", str2num(w)); + if (!NIL_P(d)) + set_hash("cwday", str2num(d)); + + return 1; +} + +static int +parse_iso21(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?\\b" +#else + BOS + FPW_COM FPT_COM + "(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_iso21_cb); +} + +static int +parse_iso22_cb(VALUE m, VALUE hash) +{ + VALUE d; + + d = rb_reg_nth_match(1, m); + set_hash("cwday", str2num(d)); + return 1; +} + +static int +parse_iso22(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "-w-(\\d)\\b" +#else + BOS + FPW_COM FPT_COM + "-w-(\\d)" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_iso22_cb); +} + +static int +parse_iso23_cb(VALUE m, VALUE hash) +{ + VALUE mon, d; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + + if (!NIL_P(mon)) + set_hash("mon", str2num(mon)); + set_hash("mday", str2num(d)); + + return 1; +} + +static int +parse_iso23(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "--(\\d{2})?-(\\d{2})\\b" +#else + BOS + FPW_COM FPT_COM + "--(\\d{2})?-(\\d{2})" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_iso23_cb); +} + +static int +parse_iso24_cb(VALUE m, VALUE hash) +{ + VALUE mon, d; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + + set_hash("mon", str2num(mon)); + if (!NIL_P(d)) + set_hash("mday", str2num(d)); + + return 1; +} + +static int +parse_iso24(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "--(\\d{2})(\\d{2})?\\b" +#else + BOS + FPW_COM FPT_COM + "--(\\d{2})(\\d{2})?" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_iso24_cb); +} + +static int +parse_iso25_cb(VALUE m, VALUE hash) +{ + VALUE y, d; + + y = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + + set_hash("year", str2num(y)); + set_hash("yday", str2num(d)); + + return 1; +} + +static int +parse_iso25(VALUE str, VALUE hash) +{ + static const char pat0_source[] = +#ifndef TIGHT_PARSER + "[,.](\\d{2}|\\d{4})-\\d{3}\\b" +#else + BOS + FPW_COM FPT_COM + "[,.](\\d{2}|\\d{4})-\\d{3}" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat0 = Qnil; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b(\\d{2}|\\d{4})-(\\d{3})\\b" +#else + BOS + FPW_COM FPT_COM + "(\\d{2}|\\d{4})-(\\d{3})" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_0(pat0); + REGCOMP_0(pat); + + if (!NIL_P(f_match(pat0, str))) + return 0; + SUBS(str, pat, parse_iso25_cb); +} + +static int +parse_iso26_cb(VALUE m, VALUE hash) +{ + VALUE d; + + d = rb_reg_nth_match(1, m); + set_hash("yday", str2num(d)); + + return 1; +} +static int +parse_iso26(VALUE str, VALUE hash) +{ + static const char pat0_source[] = +#ifndef TIGHT_PARSER + "\\d-\\d{3}\\b" +#else + BOS + FPW_COM FPT_COM + "\\d-\\d{3}" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat0 = Qnil; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b-(\\d{3})\\b" +#else + BOS + FPW_COM FPT_COM + "-(\\d{3})" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_0(pat0); + REGCOMP_0(pat); + + if (!NIL_P(f_match(pat0, str))) + return 0; + SUBS(str, pat, parse_iso26_cb); +} + +static int +parse_iso2(VALUE str, VALUE hash) +{ + if (parse_iso21(str, hash)) + goto ok; + if (parse_iso22(str, hash)) + goto ok; + if (parse_iso23(str, hash)) + goto ok; + if (parse_iso24(str, hash)) + goto ok; + if (parse_iso25(str, hash)) + goto ok; + if (parse_iso26(str, hash)) + goto ok; + return 0; + + ok: + return 1; +} + +static int +gengo(int c) +{ + int e; + + switch (c) { + case 'M': case 'm': e = 1867; break; + case 'T': case 't': e = 1911; break; + case 'S': case 's': e = 1925; break; + case 'H': case 'h': e = 1988; break; + default: e = 0; break; + } + return e; +} + +static int +parse_jis_cb(VALUE m, VALUE hash) +{ + VALUE e, y, mon, d; + int ep; + + e = rb_reg_nth_match(1, m); + y = rb_reg_nth_match(2, m); + mon = rb_reg_nth_match(3, m); + d = rb_reg_nth_match(4, m); + + ep = gengo(*RSTRING_PTR(e)); + + set_hash("year", f_add(str2num(y), INT2FIX(ep))); + set_hash("mon", str2num(mon)); + set_hash("mday", str2num(d)); + + return 1; +} + +static int +parse_jis(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b([mtsh])(\\d+)\\.(\\d+)\\.(\\d+)" +#else + BOS + FPW_COM FPT_COM + "([mtsh])(\\d+)\\.(\\d+)\\.(\\d+)" + TEE_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_jis_cb); +} + +static int +parse_vms11_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + d = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + +#ifdef TIGHT_PARSER + if (!check_apost(d, mon, y)) + return 0; +#endif + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_vms11(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "('?-?\\d+)-(" ABBR_MONTHS ")[^-/.]*" + "-('?-?\\d+)" +#else + BOS + FPW_COM FPT_COM + "([-']?\\d+)-(" DOTLESS_VALID_MONTHS ")" + "-([-']?\\d+)" + COM_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_vms11_cb); +} + +static int +parse_vms12_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + +#ifdef TIGHT_PARSER + if (!check_apost(mon, d, y)) + return 0; +#endif + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_vms12(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b(" ABBR_MONTHS ")[^-/.]*" + "-('?-?\\d+)(?:-('?-?\\d+))?" +#else + BOS + FPW_COM FPT_COM + "(" DOTLESS_VALID_MONTHS ")" + "-([-']?\\d+)(?:-([-']?\\d+))?" + COM_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_vms12_cb); +} + +static int +parse_vms(VALUE str, VALUE hash) +{ + if (parse_vms11(str, hash)) + goto ok; + if (parse_vms12(str, hash)) + goto ok; + return 0; + + ok: + return 1; +} + +static int +parse_sla_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + y = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + d = rb_reg_nth_match(3, m); + +#ifdef TIGHT_PARSER + if (!check_apost(y, mon, d)) + return 0; +#endif + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_sla(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "('?-?\\d+)/\\s*('?\\d+)(?:\\D\\s*('?-?\\d+))?" +#else + BOS + FPW_COM FPT_COM + "([-']?\\d+)/\\s*('?\\d+)(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_sla_cb); +} + +#ifdef TIGHT_PARSER +static int +parse_sla2_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + d = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(d, mon, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_sla2(VALUE str, VALUE hash) +{ + static const char pat_source[] = + BOS + FPW_COM FPT_COM + "([-']?\\d+)/\\s*(" DOTLESS_VALID_MONTHS ")(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_sla2_cb); +} + +static int +parse_sla3_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(mon, d, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_sla3(VALUE str, VALUE hash) +{ + static const char pat_source[] = + BOS + FPW_COM FPT_COM + "(" DOTLESS_VALID_MONTHS ")/\\s*([-']?\\d+)(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_sla3_cb); +} +#endif + +static int +parse_dot_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + y = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + d = rb_reg_nth_match(3, m); + +#ifdef TIGHT_PARSER + if (!check_apost(y, mon, d)) + return 0; +#endif + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_dot(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "('?-?\\d+)\\.\\s*('?\\d+)\\.\\s*('?-?\\d+)" +#else + BOS + FPW_COM FPT_COM + "([-']?\\d+)\\.\\s*(\\d+)\\.\\s*([-']?\\d+)" + COM_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_dot_cb); +} + +#ifdef TIGHT_PARSER +static int +parse_dot2_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + d = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(d, mon, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_dot2(VALUE str, VALUE hash) +{ + static const char pat_source[] = + BOS + FPW_COM FPT_COM + "([-']?\\d+)\\.\\s*(" DOTLESS_VALID_MONTHS ")(?:(?:[./])\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_dot2_cb); +} + +static int +parse_dot3_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(mon, d, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_dot3(VALUE str, VALUE hash) +{ + static const char pat_source[] = + BOS + FPW_COM FPT_COM + "(" DOTLESS_VALID_MONTHS ")\\.\\s*([-']?\\d+)(?:(?:[./])\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_dot3_cb); +} +#endif + +static int +parse_year_cb(VALUE m, VALUE hash) +{ + VALUE y; + + y = rb_reg_nth_match(1, m); + set_hash("year", str2num(y)); + return 1; +} + +static int +parse_year(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "'(\\d+)\\b" +#else + BOS + FPW_COM FPT_COM + "'(\\d+)" + COM_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_year_cb); +} + +static int +parse_mon_cb(VALUE m, VALUE hash) +{ + VALUE mon; + + mon = rb_reg_nth_match(1, m); + set_hash("mon", INT2FIX(mon_num(mon))); + return 1; +} + +static int +parse_mon(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b(" ABBR_MONTHS ")\\S*" +#else + BOS + FPW_COM FPT_COM + "(" VALID_MONTHS ")" + COM_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_mon_cb); +} + +static int +parse_mday_cb(VALUE m, VALUE hash) +{ + VALUE d; + + d = rb_reg_nth_match(1, m); + set_hash("mday", str2num(d)); + return 1; +} + +static int +parse_mday(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifndef TIGHT_PARSER + "(\\d+)(st|nd|rd|th)\\b" +#else + BOS + FPW_COM FPT_COM + "(\\d+)(st|nd|rd|th)" + COM_FPT COM_FPW + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_mday_cb); +} + +static int +n2i(const char *s, long f, long w) +{ + long e, i; + int v; + + e = f + w; + v = 0; + for (i = f; i < e; i++) { + v *= 10; + v += s[i] - '0'; + } + return v; +} + +static int +parse_ddd_cb(VALUE m, VALUE hash) +{ + VALUE s1, s2, s3, s4, s5; + const char *cs2, *cs3, *cs5; + long l2, l3, l4, l5; + + s1 = rb_reg_nth_match(1, m); + s2 = rb_reg_nth_match(2, m); + s3 = rb_reg_nth_match(3, m); + s4 = rb_reg_nth_match(4, m); + s5 = rb_reg_nth_match(5, m); + + cs2 = RSTRING_PTR(s2); + l2 = RSTRING_LEN(s2); + + switch (l2) { + case 2: + if (NIL_P(s3) && !NIL_P(s4)) + set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2))); + else + set_hash("mday", INT2FIX(n2i(cs2, 0, 2))); + break; + case 4: + if (NIL_P(s3) && !NIL_P(s4)) { + set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2))); + set_hash("min", INT2FIX(n2i(cs2, l2-4, 2))); + } + else { + set_hash("mon", INT2FIX(n2i(cs2, 0, 2))); + set_hash("mday", INT2FIX(n2i(cs2, 2, 2))); + } + break; + case 6: + if (NIL_P(s3) && !NIL_P(s4)) { + set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2))); + set_hash("min", INT2FIX(n2i(cs2, l2-4, 2))); + set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2))); + } + else { + int y = n2i(cs2, 0, 2); + if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-') + y = -y; + set_hash("year", INT2FIX(y)); + set_hash("mon", INT2FIX(n2i(cs2, 2, 2))); + set_hash("mday", INT2FIX(n2i(cs2, 4, 2))); + } + break; + case 8: + case 10: + case 12: + case 14: + if (NIL_P(s3) && !NIL_P(s4)) { + set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2))); + set_hash("min", INT2FIX(n2i(cs2, l2-4, 2))); + set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2))); + set_hash("mday", INT2FIX(n2i(cs2, l2-8, 2))); + if (l2 >= 10) + set_hash("mon", INT2FIX(n2i(cs2, l2-10, 2))); + if (l2 == 12) { + int y = n2i(cs2, l2-12, 2); + if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-') + y = -y; + set_hash("year", INT2FIX(y)); + } + if (l2 == 14) { + int y = n2i(cs2, l2-14, 4); + if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-') + y = -y; + set_hash("year", INT2FIX(y)); + set_hash("_comp", Qfalse); + } + } + else { + int y = n2i(cs2, 0, 4); + if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-') + y = -y; + set_hash("year", INT2FIX(y)); + set_hash("mon", INT2FIX(n2i(cs2, 4, 2))); + set_hash("mday", INT2FIX(n2i(cs2, 6, 2))); + if (l2 >= 10) + set_hash("hour", INT2FIX(n2i(cs2, 8, 2))); + if (l2 >= 12) + set_hash("min", INT2FIX(n2i(cs2, 10, 2))); + if (l2 >= 14) + set_hash("sec", INT2FIX(n2i(cs2, 12, 2))); + set_hash("_comp", Qfalse); + } + break; + case 3: + if (NIL_P(s3) && !NIL_P(s4)) { + set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2))); + set_hash("min", INT2FIX(n2i(cs2, l2-3, 1))); + } + else + set_hash("yday", INT2FIX(n2i(cs2, 0, 3))); + break; + case 5: + if (NIL_P(s3) && !NIL_P(s4)) { + set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2))); + set_hash("min", INT2FIX(n2i(cs2, l2-4, 2))); + set_hash("hour", INT2FIX(n2i(cs2, l2-5, 1))); + } + else { + int y = n2i(cs2, 0, 2); + if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-') + y = -y; + set_hash("year", INT2FIX(y)); + set_hash("yday", INT2FIX(n2i(cs2, 2, 3))); + } + break; + case 7: + if (NIL_P(s3) && !NIL_P(s4)) { + set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2))); + set_hash("min", INT2FIX(n2i(cs2, l2-4, 2))); + set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2))); + set_hash("mday", INT2FIX(n2i(cs2, l2-7, 1))); + } + else { + int y = n2i(cs2, 0, 4); + if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-') + y = -y; + set_hash("year", INT2FIX(y)); + set_hash("yday", INT2FIX(n2i(cs2, 4, 3))); + } + break; + } + RB_GC_GUARD(s2); + if (!NIL_P(s3)) { + cs3 = RSTRING_PTR(s3); + l3 = RSTRING_LEN(s3); + + if (!NIL_P(s4)) { + switch (l3) { + case 2: + case 4: + case 6: + set_hash("sec", INT2FIX(n2i(cs3, l3-2, 2))); + if (l3 >= 4) + set_hash("min", INT2FIX(n2i(cs3, l3-4, 2))); + if (l3 >= 6) + set_hash("hour", INT2FIX(n2i(cs3, l3-6, 2))); + break; + } + } + else { + switch (l3) { + case 2: + case 4: + case 6: + set_hash("hour", INT2FIX(n2i(cs3, 0, 2))); + if (l3 >= 4) + set_hash("min", INT2FIX(n2i(cs3, 2, 2))); + if (l3 >= 6) + set_hash("sec", INT2FIX(n2i(cs3, 4, 2))); + break; + } + } + RB_GC_GUARD(s3); + } + if (!NIL_P(s4)) { + l4 = RSTRING_LEN(s4); + + set_hash("sec_fraction", + rb_rational_new2(str2num(s4), + f_expt(INT2FIX(10), LONG2NUM(l4)))); + } + if (!NIL_P(s5)) { + cs5 = RSTRING_PTR(s5); + l5 = RSTRING_LEN(s5); + + set_hash("zone", s5); + + if (*cs5 == '[') { + char *buf = ALLOCA_N(char, l5 + 1); + char *s1, *s2, *s3; + VALUE zone; + + memcpy(buf, cs5, l5); + buf[l5 - 1] = '\0'; + + s1 = buf + 1; + s2 = strchr(buf, ':'); + if (s2) { + *s2 = '\0'; + s2++; + } + if (s2) + s3 = s2; + else + s3 = s1; + zone = rb_str_new2(s3); + set_hash("zone", zone); + if (isdigit((unsigned char)*s1)) + *--s1 = '+'; + set_hash("offset", date_zone_to_diff(rb_str_new2(s1))); + } + RB_GC_GUARD(s5); + } + + return 1; +} + +static int +parse_ddd(VALUE str, VALUE hash) +{ + static const char pat_source[] = +#ifdef TIGHT_PARSER + BOS +#endif + "([-+]?)(\\d{2,14})" + "(?:" + "\\s*" + "t?" + "\\s*" + "(\\d{2,6})?(?:[,.](\\d*))?" + ")?" + "(?:" + "\\s*" + "(" + "z\\b" + "|" + "[-+]\\d{1,4}\\b" + "|" + "\\[[-+]?\\d[^\\]]*\\]" + ")" + ")?" +#ifdef TIGHT_PARSER + EOS +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_ddd_cb); +} + +#ifndef TIGHT_PARSER +static int +parse_bc_cb(VALUE m, VALUE hash) +{ + set_hash("_bc", Qtrue); + return 1; +} + +static int +parse_bc(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\b(bc\\b|bce\\b|b\\.c\\.|b\\.c\\.e\\.)"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_bc_cb); +} + +static int +parse_frag_cb(VALUE m, VALUE hash) +{ + VALUE s, n; + + s = rb_reg_nth_match(1, m); + + if (!NIL_P(ref_hash("hour")) && NIL_P(ref_hash("mday"))) { + n = str2num(s); + if (f_ge_p(n, INT2FIX(1)) && + f_le_p(n, INT2FIX(31))) + set_hash("mday", n); + } + if (!NIL_P(ref_hash("mday")) && NIL_P(ref_hash("hour"))) { + n = str2num(s); + if (f_ge_p(n, INT2FIX(0)) && + f_le_p(n, INT2FIX(24))) + set_hash("hour", n); + } + + return 1; +} + +static int +parse_frag(VALUE str, VALUE hash) +{ + static const char pat_source[] = "\\A\\s*(\\d{1,2})\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_frag_cb); +} +#endif + +#ifdef TIGHT_PARSER +static int +parse_dummy_cb(VALUE m, VALUE hash) +{ + return 1; +} + +static int +parse_wday_only(VALUE str, VALUE hash) +{ + static const char pat_source[] = "\\A\\s*" FPW "\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_dummy_cb); +} + +static int +parse_time_only(VALUE str, VALUE hash) +{ + static const char pat_source[] = "\\A\\s*" FPT "\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_dummy_cb); +} + +static int +parse_wday_and_time(VALUE str, VALUE hash) +{ + static const char pat_source[] = "\\A\\s*(" FPW "\\s+" FPT "|" FPT "\\s+" FPW ")\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_dummy_cb); +} + +static unsigned +have_invalid_char_p(VALUE s) +{ + long i; + + for (i = 0; i < RSTRING_LEN(s); i++) + if (iscntrl((unsigned char)RSTRING_PTR(s)[i]) && + !isspace((unsigned char)RSTRING_PTR(s)[i])) + return 1; + return 0; +} +#endif + +#define HAVE_ALPHA (1<<0) +#define HAVE_DIGIT (1<<1) +#define HAVE_DASH (1<<2) +#define HAVE_DOT (1<<3) +#define HAVE_SLASH (1<<4) + +static unsigned +check_class(VALUE s) +{ + unsigned flags; + long i; + + flags = 0; + for (i = 0; i < RSTRING_LEN(s); i++) { + if (isalpha((unsigned char)RSTRING_PTR(s)[i])) + flags |= HAVE_ALPHA; + if (isdigit((unsigned char)RSTRING_PTR(s)[i])) + flags |= HAVE_DIGIT; + if (RSTRING_PTR(s)[i] == '-') + flags |= HAVE_DASH; + if (RSTRING_PTR(s)[i] == '.') + flags |= HAVE_DOT; + if (RSTRING_PTR(s)[i] == '/') + flags |= HAVE_SLASH; + } + return flags; +} + +#define HAVE_ELEM_P(x) ((check_class(str) & (x)) == (x)) + +#ifdef TIGHT_PARSER +#define PARSER_ERROR return rb_hash_new() +#endif + +VALUE +date__parse(VALUE str, VALUE comp) +{ + VALUE backref, hash; + +#ifdef TIGHT_PARSER + if (have_invalid_char_p(str)) + PARSER_ERROR; +#endif + + backref = rb_backref_get(); + rb_match_busy(backref); + + { + static const char pat_source[] = +#ifndef TIGHT_PARSER + "[^-+',./:@[:alnum:]\\[\\]]+" +#else + "[^[:graph:]]+" +#endif + ; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + str = rb_str_dup(str); + f_gsub_bang(str, pat, asp_string()); + } + + hash = rb_hash_new(); + set_hash("_comp", comp); + + if (HAVE_ELEM_P(HAVE_ALPHA)) + parse_day(str, hash); + if (HAVE_ELEM_P(HAVE_DIGIT)) + parse_time(str, hash); + +#ifdef TIGHT_PARSER + if (HAVE_ELEM_P(HAVE_ALPHA)) + parse_era(str, hash); +#endif + + if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT)) { + if (parse_eu(str, hash)) + goto ok; + if (parse_us(str, hash)) + goto ok; + } + if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DASH)) + if (parse_iso(str, hash)) + goto ok; + if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DOT)) + if (parse_jis(str, hash)) + goto ok; + if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_DASH)) + if (parse_vms(str, hash)) + goto ok; + if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_SLASH)) + if (parse_sla(str, hash)) + goto ok; +#ifdef TIGHT_PARSER + if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_SLASH)) { + if (parse_sla2(str, hash)) + goto ok; + if (parse_sla3(str, hash)) + goto ok; + } +#endif + if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DOT)) + if (parse_dot(str, hash)) + goto ok; +#ifdef TIGHT_PARSER + if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_DOT)) { + if (parse_dot2(str, hash)) + goto ok; + if (parse_dot3(str, hash)) + goto ok; + } +#endif + if (HAVE_ELEM_P(HAVE_DIGIT)) + if (parse_iso2(str, hash)) + goto ok; + if (HAVE_ELEM_P(HAVE_DIGIT)) + if (parse_year(str, hash)) + goto ok; + if (HAVE_ELEM_P(HAVE_ALPHA)) + if (parse_mon(str, hash)) + goto ok; + if (HAVE_ELEM_P(HAVE_DIGIT)) + if (parse_mday(str, hash)) + goto ok; + if (HAVE_ELEM_P(HAVE_DIGIT)) + if (parse_ddd(str, hash)) + goto ok; + +#ifdef TIGHT_PARSER + if (parse_wday_only(str, hash)) + goto ok; + if (parse_time_only(str, hash)) + goto ok; + if (parse_wday_and_time(str, hash)) + goto ok; + + PARSER_ERROR; /* not found */ +#endif + + ok: +#ifndef TIGHT_PARSER + if (HAVE_ELEM_P(HAVE_ALPHA)) + parse_bc(str, hash); + if (HAVE_ELEM_P(HAVE_DIGIT)) + parse_frag(str, hash); +#endif + + { + if (RTEST(ref_hash("_bc"))) { + VALUE y; + + y = ref_hash("cwyear"); + if (!NIL_P(y)) { + y = f_add(f_negate(y), INT2FIX(1)); + set_hash("cwyear", y); + } + y = ref_hash("year"); + if (!NIL_P(y)) { + y = f_add(f_negate(y), INT2FIX(1)); + set_hash("year", y); + } + } + + if (RTEST(ref_hash("_comp"))) { + VALUE y; + + y = ref_hash("cwyear"); + if (!NIL_P(y)) + if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) { + if (f_ge_p(y, INT2FIX(69))) + set_hash("cwyear", f_add(y, INT2FIX(1900))); + else + set_hash("cwyear", f_add(y, INT2FIX(2000))); + } + y = ref_hash("year"); + if (!NIL_P(y)) + if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) { + if (f_ge_p(y, INT2FIX(69))) + set_hash("year", f_add(y, INT2FIX(1900))); + else + set_hash("year", f_add(y, INT2FIX(2000))); + } + } + + } + + del_hash("_bc"); + del_hash("_comp"); + + { + VALUE zone = ref_hash("zone"); + if (!NIL_P(zone) && NIL_P(ref_hash("offset"))) + set_hash("offset", date_zone_to_diff(zone)); + } + + rb_backref_set(backref); + + return hash; +} + +static VALUE +comp_year69(VALUE y) +{ + if (f_ge_p(y, INT2FIX(69))) + return f_add(y, INT2FIX(1900)); + return f_add(y, INT2FIX(2000)); +} + +static VALUE +comp_year50(VALUE y) +{ + if (f_ge_p(y, INT2FIX(50))) + return f_add(y, INT2FIX(1900)); + return f_add(y, INT2FIX(2000)); +} + +static VALUE +sec_fraction(VALUE f) +{ + return rb_rational_new2(str2num(f), + f_expt(INT2FIX(10), + LONG2NUM(RSTRING_LEN(f)))); +} + +#define SNUM 14 + +static int +iso8601_ext_datetime_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1], y; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + if (!NIL_P(s[3])) { + set_hash("mday", str2num(s[3])); + if (strcmp(RSTRING_PTR(s[1]), "-") != 0) { + y = str2num(s[1]); + if (RSTRING_LEN(s[1]) < 4) + y = comp_year69(y); + set_hash("year", y); + } + if (NIL_P(s[2])) { + if (strcmp(RSTRING_PTR(s[1]), "-") != 0) + return 0; + } + else + set_hash("mon", str2num(s[2])); + } + else if (!NIL_P(s[5])) { + set_hash("yday", str2num(s[5])); + if (!NIL_P(s[4])) { + y = str2num(s[4]); + if (RSTRING_LEN(s[4]) < 4) + y = comp_year69(y); + set_hash("year", y); + } + } + else if (!NIL_P(s[8])) { + set_hash("cweek", str2num(s[7])); + set_hash("cwday", str2num(s[8])); + if (!NIL_P(s[6])) { + y = str2num(s[6]); + if (RSTRING_LEN(s[6]) < 4) + y = comp_year69(y); + set_hash("cwyear", y); + } + } + else if (!NIL_P(s[9])) { + set_hash("cwday", str2num(s[9])); + } + if (!NIL_P(s[10])) { + set_hash("hour", str2num(s[10])); + set_hash("min", str2num(s[11])); + if (!NIL_P(s[12])) + set_hash("sec", str2num(s[12])); + } + if (!NIL_P(s[13])) { + set_hash("sec_fraction", sec_fraction(s[13])); + } + if (!NIL_P(s[14])) { + set_hash("zone", s[14]); + set_hash("offset", date_zone_to_diff(s[14])); + } + + return 1; +} + +static int +iso8601_ext_datetime(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(?:([-+]?\\d{2,}|-)-(\\d{2})?-(\\d{2})|" + "([-+]?\\d{2,})?-(\\d{3})|" + "(\\d{4}|\\d{2})?-w(\\d{2})-(\\d)|" + "-w-(\\d))" + "(?:t" + "(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?)?" + "(z|[-+]\\d{2}(?::?\\d{2})?)?)?\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, iso8601_ext_datetime_cb); +} + +#undef SNUM +#define SNUM 17 + +static int +iso8601_bas_datetime_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1], y; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + if (!NIL_P(s[3])) { + set_hash("mday", str2num(s[3])); + if (strcmp(RSTRING_PTR(s[1]), "--") != 0) { + y = str2num(s[1]); + if (RSTRING_LEN(s[1]) < 4) + y = comp_year69(y); + set_hash("year", y); + } + if (*RSTRING_PTR(s[2]) == '-') { + if (strcmp(RSTRING_PTR(s[1]), "--") != 0) + return 0; + } + else + set_hash("mon", str2num(s[2])); + } + else if (!NIL_P(s[5])) { + set_hash("yday", str2num(s[5])); + y = str2num(s[4]); + if (RSTRING_LEN(s[4]) < 4) + y = comp_year69(y); + set_hash("year", y); + } + else if (!NIL_P(s[6])) { + set_hash("yday", str2num(s[6])); + } + else if (!NIL_P(s[9])) { + set_hash("cweek", str2num(s[8])); + set_hash("cwday", str2num(s[9])); + y = str2num(s[7]); + if (RSTRING_LEN(s[7]) < 4) + y = comp_year69(y); + set_hash("cwyear", y); + } + else if (!NIL_P(s[11])) { + set_hash("cweek", str2num(s[10])); + set_hash("cwday", str2num(s[11])); + } + else if (!NIL_P(s[12])) { + set_hash("cwday", str2num(s[12])); + } + if (!NIL_P(s[13])) { + set_hash("hour", str2num(s[13])); + set_hash("min", str2num(s[14])); + if (!NIL_P(s[15])) + set_hash("sec", str2num(s[15])); + } + if (!NIL_P(s[16])) { + set_hash("sec_fraction", sec_fraction(s[16])); + } + if (!NIL_P(s[17])) { + set_hash("zone", s[17]); + set_hash("offset", date_zone_to_diff(s[17])); + } + + return 1; +} + +static int +iso8601_bas_datetime(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(?:([-+]?(?:\\d{4}|\\d{2})|--)(\\d{2}|-)(\\d{2})|" + "([-+]?(?:\\d{4}|\\d{2}))(\\d{3})|" + "-(\\d{3})|" + "(\\d{4}|\\d{2})w(\\d{2})(\\d)|" + "-w(\\d{2})(\\d)|" + "-w-(\\d))" + "(?:t?" + "(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?)?" + "(z|[-+]\\d{2}(?:\\d{2})?)?)?\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, iso8601_bas_datetime_cb); +} + +#undef SNUM +#define SNUM 5 + +static int +iso8601_ext_time_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1]; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + set_hash("hour", str2num(s[1])); + set_hash("min", str2num(s[2])); + if (!NIL_P(s[3])) + set_hash("sec", str2num(s[3])); + if (!NIL_P(s[4])) + set_hash("sec_fraction", sec_fraction(s[4])); + if (!NIL_P(s[5])) { + set_hash("zone", s[5]); + set_hash("offset", date_zone_to_diff(s[5])); + } + + return 1; +} + +#define iso8601_bas_time_cb iso8601_ext_time_cb + +static int +iso8601_ext_time(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?" + "(z|[-+]\\d{2}(:?\\d{2})?)?)?\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, iso8601_ext_time_cb); +} + +static int +iso8601_bas_time(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?" + "(z|[-+]\\d{2}(\\d{2})?)?)?\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, iso8601_bas_time_cb); +} + +VALUE +date__iso8601(VALUE str) +{ + VALUE backref, hash; + + backref = rb_backref_get(); + rb_match_busy(backref); + + hash = rb_hash_new(); + + if (iso8601_ext_datetime(str, hash)) + goto ok; + if (iso8601_bas_datetime(str, hash)) + goto ok; + if (iso8601_ext_time(str, hash)) + goto ok; + if (iso8601_bas_time(str, hash)) + goto ok; + + ok: + rb_backref_set(backref); + + return hash; +} + +#undef SNUM +#define SNUM 8 + +static int +rfc3339_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1]; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + set_hash("year", str2num(s[1])); + set_hash("mon", str2num(s[2])); + set_hash("mday", str2num(s[3])); + set_hash("hour", str2num(s[4])); + set_hash("min", str2num(s[5])); + set_hash("sec", str2num(s[6])); + set_hash("zone", s[8]); + set_hash("offset", date_zone_to_diff(s[8])); + if (!NIL_P(s[7])) + set_hash("sec_fraction", sec_fraction(s[7])); + + return 1; +} + +static int +rfc3339(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(-?\\d{4})-(\\d{2})-(\\d{2})" + "(?:t|\\s)" + "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?" + "(z|[-+]\\d{2}:\\d{2})\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, rfc3339_cb); +} + +VALUE +date__rfc3339(VALUE str) +{ + VALUE backref, hash; + + backref = rb_backref_get(); + rb_match_busy(backref); + + hash = rb_hash_new(); + rfc3339(str, hash); + rb_backref_set(backref); + return hash; +} + +#undef SNUM +#define SNUM 8 + +static int +xmlschema_datetime_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1]; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + set_hash("year", str2num(s[1])); + if (!NIL_P(s[2])) + set_hash("mon", str2num(s[2])); + if (!NIL_P(s[3])) + set_hash("mday", str2num(s[3])); + if (!NIL_P(s[4])) + set_hash("hour", str2num(s[4])); + if (!NIL_P(s[5])) + set_hash("min", str2num(s[5])); + if (!NIL_P(s[6])) + set_hash("sec", str2num(s[6])); + if (!NIL_P(s[7])) + set_hash("sec_fraction", sec_fraction(s[7])); + if (!NIL_P(s[8])) { + set_hash("zone", s[8]); + set_hash("offset", date_zone_to_diff(s[8])); + } + + return 1; +} + +static int +xmlschema_datetime(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(-?\\d{4,})(?:-(\\d{2})(?:-(\\d{2}))?)?" + "(?:t" + "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?)?" + "(z|[-+]\\d{2}:\\d{2})?\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, xmlschema_datetime_cb); +} + +#undef SNUM +#define SNUM 5 + +static int +xmlschema_time_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1]; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + set_hash("hour", str2num(s[1])); + set_hash("min", str2num(s[2])); + if (!NIL_P(s[3])) + set_hash("sec", str2num(s[3])); + if (!NIL_P(s[4])) + set_hash("sec_fraction", sec_fraction(s[4])); + if (!NIL_P(s[5])) { + set_hash("zone", s[5]); + set_hash("offset", date_zone_to_diff(s[5])); + } + + return 1; +} + +static int +xmlschema_time(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?" + "(z|[-+]\\d{2}:\\d{2})?\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, xmlschema_time_cb); +} + +#undef SNUM +#define SNUM 4 + +static int +xmlschema_trunc_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1]; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + if (!NIL_P(s[1])) + set_hash("mon", str2num(s[1])); + if (!NIL_P(s[2])) + set_hash("mday", str2num(s[2])); + if (!NIL_P(s[3])) + set_hash("mday", str2num(s[3])); + if (!NIL_P(s[4])) { + set_hash("zone", s[4]); + set_hash("offset", date_zone_to_diff(s[4])); + } + + return 1; +} + +static int +xmlschema_trunc(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(?:--(\\d{2})(?:-(\\d{2}))?|---(\\d{2}))" + "(z|[-+]\\d{2}:\\d{2})?\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, xmlschema_trunc_cb); +} + +VALUE +date__xmlschema(VALUE str) +{ + VALUE backref, hash; + + backref = rb_backref_get(); + rb_match_busy(backref); + + hash = rb_hash_new(); + + if (xmlschema_datetime(str, hash)) + goto ok; + if (xmlschema_time(str, hash)) + goto ok; + if (xmlschema_trunc(str, hash)) + goto ok; + + ok: + rb_backref_set(backref); + + return hash; +} + +#undef SNUM +#define SNUM 8 + +static int +rfc2822_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1], y; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + if (!NIL_P(s[1])) { + set_hash("wday", INT2FIX(day_num(s[1]))); + } + set_hash("mday", str2num(s[2])); + set_hash("mon", INT2FIX(mon_num(s[3]))); + y = str2num(s[4]); + if (RSTRING_LEN(s[4]) < 4) + y = comp_year50(y); + set_hash("year", y); + set_hash("hour", str2num(s[5])); + set_hash("min", str2num(s[6])); + if (!NIL_P(s[7])) + set_hash("sec", str2num(s[7])); + set_hash("zone", s[8]); + set_hash("offset", date_zone_to_diff(s[8])); + + return 1; +} + +static int +rfc2822(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(?:(" ABBR_DAYS ")\\s*,\\s+)?" + "(\\d{1,2})\\s+" + "(" ABBR_MONTHS ")\\s+" + "(-?\\d{2,})\\s+" + "(\\d{2}):(\\d{2})(?::(\\d{2}))?\\s*" + "([-+]\\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, rfc2822_cb); +} + +VALUE +date__rfc2822(VALUE str) +{ + VALUE backref, hash; + + backref = rb_backref_get(); + rb_match_busy(backref); + + hash = rb_hash_new(); + rfc2822(str, hash); + rb_backref_set(backref); + return hash; +} + +#undef SNUM +#define SNUM 8 + +static int +httpdate_type1_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1]; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + set_hash("wday", INT2FIX(day_num(s[1]))); + set_hash("mday", str2num(s[2])); + set_hash("mon", INT2FIX(mon_num(s[3]))); + set_hash("year", str2num(s[4])); + set_hash("hour", str2num(s[5])); + set_hash("min", str2num(s[6])); + set_hash("sec", str2num(s[7])); + set_hash("zone", s[8]); + set_hash("offset", INT2FIX(0)); + + return 1; +} + +static int +httpdate_type1(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(" ABBR_DAYS ")\\s*,\\s+" + "(\\d{2})\\s+" + "(" ABBR_MONTHS ")\\s+" + "(-?\\d{4})\\s+" + "(\\d{2}):(\\d{2}):(\\d{2})\\s+" + "(gmt)\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, httpdate_type1_cb); +} + +#undef SNUM +#define SNUM 8 + +static int +httpdate_type2_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1], y; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + set_hash("wday", INT2FIX(day_num(s[1]))); + set_hash("mday", str2num(s[2])); + set_hash("mon", INT2FIX(mon_num(s[3]))); + y = str2num(s[4]); + if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) + y = comp_year69(y); + set_hash("year", y); + set_hash("hour", str2num(s[5])); + set_hash("min", str2num(s[6])); + set_hash("sec", str2num(s[7])); + set_hash("zone", s[8]); + set_hash("offset", INT2FIX(0)); + + return 1; +} + +static int +httpdate_type2(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(" DAYS ")\\s*,\\s+" + "(\\d{2})\\s*-\\s*" + "(" ABBR_MONTHS ")\\s*-\\s*" + "(\\d{2})\\s+" + "(\\d{2}):(\\d{2}):(\\d{2})\\s+" + "(gmt)\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, httpdate_type2_cb); +} + +#undef SNUM +#define SNUM 7 + +static int +httpdate_type3_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1]; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + set_hash("wday", INT2FIX(day_num(s[1]))); + set_hash("mon", INT2FIX(mon_num(s[2]))); + set_hash("mday", str2num(s[3])); + set_hash("hour", str2num(s[4])); + set_hash("min", str2num(s[5])); + set_hash("sec", str2num(s[6])); + set_hash("year", str2num(s[7])); + + return 1; +} + +static int +httpdate_type3(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*(" ABBR_DAYS ")\\s+" + "(" ABBR_MONTHS ")\\s+" + "(\\d{1,2})\\s+" + "(\\d{2}):(\\d{2}):(\\d{2})\\s+" + "(\\d{4})\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, httpdate_type3_cb); +} + +VALUE +date__httpdate(VALUE str) +{ + VALUE backref, hash; + + backref = rb_backref_get(); + rb_match_busy(backref); + + hash = rb_hash_new(); + + if (httpdate_type1(str, hash)) + goto ok; + if (httpdate_type2(str, hash)) + goto ok; + if (httpdate_type3(str, hash)) + goto ok; + + ok: + rb_backref_set(backref); + + return hash; +} + +#undef SNUM +#define SNUM 9 + +static int +jisx0301_cb(VALUE m, VALUE hash) +{ + VALUE s[SNUM + 1]; + int ep; + + { + int i; + s[0] = Qnil; + for (i = 1; i <= SNUM; i++) + s[i] = rb_reg_nth_match(i, m); + } + + ep = gengo(NIL_P(s[1]) ? 'h' : *RSTRING_PTR(s[1])); + set_hash("year", f_add(str2num(s[2]), INT2FIX(ep))); + set_hash("mon", str2num(s[3])); + set_hash("mday", str2num(s[4])); + if (!NIL_P(s[5])) { + set_hash("hour", str2num(s[5])); + if (!NIL_P(s[6])) + set_hash("min", str2num(s[6])); + if (!NIL_P(s[7])) + set_hash("sec", str2num(s[7])); + } + if (!NIL_P(s[8])) + set_hash("sec_fraction", sec_fraction(s[8])); + if (!NIL_P(s[9])) { + set_hash("zone", s[9]); + set_hash("offset", date_zone_to_diff(s[9])); + } + + return 1; +} + +static int +jisx0301(VALUE str, VALUE hash) +{ + static const char pat_source[] = + "\\A\\s*([mtsh])?(\\d{2})\\.(\\d{2})\\.(\\d{2})" + "(?:t" + "(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d*))?)?" + "(z|[-+]\\d{2}(?::?\\d{2})?)?)?)?\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + MATCH(str, pat, jisx0301_cb); +} + +VALUE +date__jisx0301(VALUE str) +{ + VALUE backref, hash; + + backref = rb_backref_get(); + rb_match_busy(backref); + + hash = rb_hash_new(); + if (jisx0301(str, hash)) + goto ok; + hash = date__iso8601(str); + + ok: + rb_backref_set(backref); + return hash; +} + +/* +Local variables: +c-file-style: "ruby" +End: +*/ -- cgit v1.2.3