Ruby  2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
date_parse.c
Go to the documentation of this file.
1 /*
2  date_parse.c: Coded by Tadayoshi Funaba 2011,2012
3 */
4 
5 #include "ruby.h"
6 #include "ruby/encoding.h"
7 #include "ruby/re.h"
8 #include <ctype.h>
9 
10 RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y);
11 RUBY_EXTERN unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow);
12 
13 /* #define TIGHT_PARSER */
14 
15 #define sizeof_array(o) (sizeof o / sizeof o[0])
16 
17 #define f_negate(x) rb_funcall(x, rb_intern("-@"), 0)
18 #define f_add(x,y) rb_funcall(x, '+', 1, y)
19 #define f_sub(x,y) rb_funcall(x, '-', 1, y)
20 #define f_mul(x,y) rb_funcall(x, '*', 1, y)
21 #define f_div(x,y) rb_funcall(x, '/', 1, y)
22 #define f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y)
23 #define f_mod(x,y) rb_funcall(x, '%', 1, y)
24 #define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y)
25 
26 #define f_lt_p(x,y) rb_funcall(x, '<', 1, y)
27 #define f_gt_p(x,y) rb_funcall(x, '>', 1, y)
28 #define f_le_p(x,y) rb_funcall(x, rb_intern("<="), 1, y)
29 #define f_ge_p(x,y) rb_funcall(x, rb_intern(">="), 1, y)
30 
31 #define f_to_s(x) rb_funcall(x, rb_intern("to_s"), 0)
32 
33 #define f_match(r,s) rb_funcall(r, rb_intern("match"), 1, s)
34 #define f_aref(o,i) rb_funcall(o, rb_intern("[]"), 1, i)
35 #define f_aref2(o,i,j) rb_funcall(o, rb_intern("[]"), 2, i, j)
36 #define f_begin(o,i) rb_funcall(o, rb_intern("begin"), 1, i)
37 #define f_end(o,i) rb_funcall(o, rb_intern("end"), 1, i)
38 #define f_aset(o,i,v) rb_funcall(o, rb_intern("[]="), 2, i, v)
39 #define f_aset2(o,i,j,v) rb_funcall(o, rb_intern("[]="), 3, i, j, v)
40 #define f_sub_bang(s,r,x) rb_funcall(s, rb_intern("sub!"), 2, r, x)
41 #define f_gsub_bang(s,r,x) rb_funcall(s, rb_intern("gsub!"), 2, r, x)
42 
43 #define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k"")), v)
44 #define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k"")))
45 #define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k"")))
46 
47 #define cstr2num(s) rb_cstr_to_inum(s, 10, 0)
48 #define str2num(s) rb_str_to_inum(s, 10, 0)
49 
50 static const char abbr_days[][4] = {
51  "sun", "mon", "tue", "wed",
52  "thu", "fri", "sat"
53 };
54 
55 static const char abbr_months[][4] = {
56  "jan", "feb", "mar", "apr", "may", "jun",
57  "jul", "aug", "sep", "oct", "nov", "dec"
58 };
59 
60 #define issign(c) ((c) == '-' || (c) == '+')
61 #define asp_string() rb_str_new(" ", 1)
62 #ifdef TIGHT_PARSER
63 #define asuba_string() rb_str_new("\001", 1)
64 #define asubb_string() rb_str_new("\002", 1)
65 #define asubw_string() rb_str_new("\027", 1)
66 #define asubt_string() rb_str_new("\024", 1)
67 #endif
68 
69 static size_t
70 digit_span(const char *s, const char *e)
71 {
72  size_t i = 0;
73  while (s + i < e && isdigit(s[i])) i++;
74  return i;
75 }
76 
77 static void
78 s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc)
79 {
80  VALUE vbuf = 0;
81  VALUE c = Qnil;
82 
83  if (!RB_TYPE_P(m, T_STRING))
84  m = f_to_s(m);
85 
86  if (!NIL_P(y) && !NIL_P(m) && NIL_P(d)) {
87  VALUE oy = y;
88  VALUE om = m;
89  VALUE od = d;
90 
91  y = od;
92  m = oy;
93  d = om;
94  }
95 
96  if (NIL_P(y)) {
97  if (!NIL_P(d) && RSTRING_LEN(d) > 2) {
98  y = d;
99  d = Qnil;
100  }
101  if (!NIL_P(d) && RSTRING_LEN(d) > 0 && *RSTRING_PTR(d) == '\'') {
102  y = d;
103  d = Qnil;
104  }
105  }
106 
107  if (!NIL_P(y)) {
108  const char *s, *bp, *ep;
109  size_t l;
110 
111  s = RSTRING_PTR(y);
112  ep = RSTRING_END(y);
113  while (s < ep && !issign(*s) && !isdigit(*s))
114  s++;
115  if (s >= ep) goto no_date;
116  bp = s;
117  if (issign((unsigned char)*s))
118  s++;
119  l = digit_span(s, ep);
120  ep = s + l;
121  if (*ep) {
122  y = d;
123  d = rb_str_new(bp, ep - bp);
124  }
125  no_date:;
126  }
127 
128  if (!NIL_P(m)) {
129  const char *s;
130 
131  s = RSTRING_PTR(m);
132  if (*s == '\'' || RSTRING_LEN(m) > 2) {
133  /* us -> be */
134  VALUE oy = y;
135  VALUE om = m;
136  VALUE od = d;
137 
138  y = om;
139  m = od;
140  d = oy;
141  }
142  }
143 
144  if (!NIL_P(d)) {
145  const char *s;
146 
147  s = RSTRING_PTR(d);
148  if (*s == '\'' || RSTRING_LEN(d) > 2) {
149  VALUE oy = y;
150  VALUE od = d;
151 
152  y = od;
153  d = oy;
154  }
155  }
156 
157  if (!NIL_P(y)) {
158  const char *s, *bp, *ep;
159  int sign = 0;
160  size_t l;
161  VALUE iy;
162 
163  s = RSTRING_PTR(y);
164  ep = RSTRING_END(y);
165  while (s < ep && !issign(*s) && !isdigit(*s))
166  s++;
167  if (s >= ep) goto no_year;
168  bp = s;
169  if (issign(*s)) {
170  s++;
171  sign = 1;
172  }
173  if (sign)
174  c = Qfalse;
175  l = digit_span(s, ep);
176  ep = s + l;
177  if (l > 2)
178  c = Qfalse;
179  {
180  char *buf;
181 
182  buf = ALLOCV_N(char, vbuf, ep - bp + 1);
183  memcpy(buf, bp, ep - bp);
184  buf[ep - bp] = '\0';
185  iy = cstr2num(buf);
186  ALLOCV_END(vbuf);
187  }
188  set_hash("year", iy);
189  no_year:;
190  }
191 
192  if (bc)
193  set_hash("_bc", Qtrue);
194 
195  if (!NIL_P(m)) {
196  const char *s, *bp, *ep;
197  size_t l;
198  VALUE im;
199 
200  s = RSTRING_PTR(m);
201  ep = RSTRING_END(m);
202  while (s < ep && !isdigit(*s))
203  s++;
204  if (s >= ep) goto no_month;
205  bp = s;
206  l = digit_span(s, ep);
207  ep = s + l;
208  {
209  char *buf;
210 
211  buf = ALLOCV_N(char, vbuf, ep - bp + 1);
212  memcpy(buf, bp, ep - bp);
213  buf[ep - bp] = '\0';
214  im = cstr2num(buf);
215  ALLOCV_END(vbuf);
216  }
217  set_hash("mon", im);
218  no_month:;
219  }
220 
221  if (!NIL_P(d)) {
222  const char *s, *bp, *ep;
223  size_t l;
224  VALUE id;
225 
226  s = RSTRING_PTR(d);
227  ep = RSTRING_END(d);
228  while (s < ep && !isdigit(*s))
229  s++;
230  if (s >= ep) goto no_mday;
231  bp = s;
232  l = digit_span(s, ep);
233  ep = s + l;
234  {
235  char *buf;
236 
237  buf = ALLOCV_N(char, vbuf, ep - bp + 1);
238  memcpy(buf, bp, ep - bp);
239  buf[ep - bp] = '\0';
240  id = cstr2num(buf);
241  ALLOCV_END(vbuf);
242  }
243  set_hash("mday", id);
244  no_mday:;
245  }
246 
247  if (!NIL_P(c))
248  set_hash("_comp", c);
249 }
250 
251 #define DAYS "sunday|monday|tuesday|wednesday|thursday|friday|saturday"
252 #define MONTHS "january|february|march|april|may|june|july|august|september|october|november|december"
253 #define ABBR_DAYS "sun|mon|tue|wed|thu|fri|sat"
254 #define ABBR_MONTHS "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec"
255 
256 #ifdef TIGHT_PARSER
257 #define VALID_DAYS "(?:" DAYS ")" "|(?:tues|wednes|thurs|thur|" ABBR_DAYS ")\\.?"
258 #define VALID_MONTHS "(?:" MONTHS ")" "|(?:sept|" ABBR_MONTHS ")\\.?"
259 #define DOTLESS_VALID_MONTHS "(?:" MONTHS ")" "|(?:sept|" ABBR_MONTHS ")"
260 #define BOS "\\A\\s*"
261 #define FPA "\\001"
262 #define FPB "\\002"
263 #define FPW "\\027"
264 #define FPT "\\024"
265 #define FPW_COM "\\s*(?:" FPW "\\s*,?)?\\s*"
266 #define FPT_COM "\\s*(?:" FPT "\\s*,?)?\\s*"
267 #define COM_FPW "\\s*(?:,?\\s*" FPW ")?\\s*"
268 #define COM_FPT "\\s*(?:,?\\s*(?:@|\\b[aA][tT]\\b)?\\s*" FPT ")?\\s*"
269 #define TEE_FPT "\\s*(?:[tT]?" FPT ")?"
270 #define EOS "\\s*\\z"
271 #endif
272 
273 static VALUE
274 regcomp(const char *source, long len, int opt)
275 {
276  VALUE pat;
277 
278  pat = rb_reg_new(source, len, opt);
280  return pat;
281 }
282 
283 #define REGCOMP(pat,opt) \
284 do { \
285  if (NIL_P(pat)) \
286  pat = regcomp(pat##_source, sizeof pat##_source - 1, opt); \
287 } while (0)
288 
289 #define REGCOMP_0(pat) REGCOMP(pat, 0)
290 #define REGCOMP_I(pat) REGCOMP(pat, ONIG_OPTION_IGNORECASE)
291 
292 #define MATCH(s,p,c) \
293 do { \
294  return match(s, p, hash, c); \
295 } while (0)
296 
297 static int
298 match(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE))
299 {
300  VALUE m;
301 
302  m = f_match(pat, str);
303 
304  if (NIL_P(m))
305  return 0;
306 
307  (*cb)(m, hash);
308 
309  return 1;
310 }
311 
312 static int
313 subx(VALUE str, VALUE rep, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE))
314 {
315  VALUE m;
316 
317  m = f_match(pat, str);
318 
319  if (NIL_P(m))
320  return 0;
321 
322  {
323  VALUE be, en;
324 
325  be = f_begin(m, INT2FIX(0));
326  en = f_end(m, INT2FIX(0));
327  f_aset2(str, be, LONG2NUM(NUM2LONG(en) - NUM2LONG(be)), rep);
328  (*cb)(m, hash);
329  }
330 
331  return 1;
332 }
333 
334 #define SUBS(s,p,c) \
335 do { \
336  return subx(s, asp_string(), p, hash, c); \
337 } while (0)
338 
339 #ifdef TIGHT_PARSER
340 #define SUBA(s,p,c) \
341 do { \
342  return subx(s, asuba_string(), p, hash, c); \
343 } while (0)
344 
345 #define SUBB(s,p,c) \
346 do { \
347  return subx(s, asubb_string(), p, hash, c); \
348 } while (0)
349 
350 #define SUBW(s,p,c) \
351 do { \
352  return subx(s, asubw_string(), p, hash, c); \
353 } while (0)
354 
355 #define SUBT(s,p,c) \
356 do { \
357  return subx(s, asubt_string(), p, hash, c); \
358 } while (0)
359 #endif
360 
361 #include "zonetab.h"
362 
363 static int
364 str_end_with_word(const char *s, long l, const char *w)
365 {
366  int n = (int)strlen(w);
367  if (l <= n || !isspace(s[l - n - 1])) return 0;
368  if (strncasecmp(&s[l - n], w, n)) return 0;
369  do ++n; while (l > n && isspace(s[l - n - 1]));
370  return n;
371 }
372 
373 static long
374 shrunk_size(const char *s, long l)
375 {
376  long i, ni;
377  int sp = 0;
378  for (i = ni = 0; i < l; ++i) {
379  if (!isspace(s[i])) {
380  if (sp) ni++;
381  sp = 0;
382  ni++;
383  }
384  else {
385  sp = 1;
386  }
387  }
388  return ni < l ? ni : 0;
389 }
390 
391 static long
392 shrink_space(char *d, const char *s, long l)
393 {
394  long i, ni;
395  int sp = 0;
396  for (i = ni = 0; i < l; ++i) {
397  if (!isspace(s[i])) {
398  if (sp) d[ni++] = ' ';
399  sp = 0;
400  d[ni++] = s[i];
401  }
402  else {
403  sp = 1;
404  }
405  }
406  return ni;
407 }
408 
409 VALUE
411 {
412  VALUE offset = Qnil;
413  VALUE vbuf = 0;
414  long l = RSTRING_LEN(str);
415  const char *s = RSTRING_PTR(str);
416 
417  {
418  int dst = 0;
419  int w;
420 
421  if ((w = str_end_with_word(s, l, "time")) > 0) {
422  int wtime = w;
423  l -= w;
424  if ((w = str_end_with_word(s, l, "standard")) > 0) {
425  l -= w;
426  }
427  else if ((w = str_end_with_word(s, l, "daylight")) > 0) {
428  l -= w;
429  dst = 1;
430  }
431  else {
432  l += wtime;
433  }
434  }
435  else if ((w = str_end_with_word(s, l, "dst")) > 0) {
436  l -= w;
437  dst = 1;
438  }
439  {
440  long sl = shrunk_size(s, l);
441  if (sl > 0 && sl <= MAX_WORD_LENGTH) {
442  char *d = ALLOCV_N(char, vbuf, sl);
443  l = shrink_space(d, s, l);
444  s = d;
445  }
446  }
447  if (l > 0 && l <= MAX_WORD_LENGTH) {
448  const struct zone *z = zonetab(s, (unsigned int)l);
449  if (z) {
450  int d = z->offset;
451  if (dst)
452  d += 3600;
453  offset = INT2FIX(d);
454  goto ok;
455  }
456  }
457  {
458  char *p;
459  int sign = 0;
460  long hour = 0, min = 0, sec = 0;
461 
462  if (l > 3 &&
463  (strncasecmp(s, "gmt", 3) == 0 ||
464  strncasecmp(s, "utc", 3) == 0)) {
465  s += 3;
466  l -= 3;
467  }
468  if (issign(*s)) {
469  sign = *s == '-';
470  s++;
471  l--;
472 
473  hour = STRTOUL(s, &p, 10);
474  if (*p == ':') {
475  s = ++p;
476  min = STRTOUL(s, &p, 10);
477  if (*p == ':') {
478  s = ++p;
479  sec = STRTOUL(s, &p, 10);
480  }
481  goto num;
482  }
483  if (*p == ',' || *p == '.') {
484  char *e = 0;
485  p++;
486  min = STRTOUL(p, &e, 10) * 3600;
487  if (sign) {
488  hour = -hour;
489  min = -min;
490  }
492  rb_int_positive_pow(10, (int)(e - p)));
493  offset = f_add(INT2FIX(hour * 3600), offset);
494  goto ok;
495  }
496  else if (l > 2) {
497  size_t n;
498  int ov;
499 
500  if (l >= 1)
501  hour = ruby_scan_digits(&s[0], 2 - l % 2, 10, &n, &ov);
502  if (l >= 3)
503  min = ruby_scan_digits(&s[2 - l % 2], 2, 10, &n, &ov);
504  if (l >= 5)
505  sec = ruby_scan_digits(&s[4 - l % 2], 2, 10, &n, &ov);
506  goto num;
507  }
508  num:
509  sec += min * 60 + hour * 3600;
510  if (sign) sec = -sec;
511  offset = INT2FIX(sec);
512  }
513  }
514  }
515  RB_GC_GUARD(str);
516  ok:
517  ALLOCV_END(vbuf);
518  return offset;
519 }
520 
521 static int
522 day_num(VALUE s)
523 {
524  int i;
525 
526  for (i = 0; i < (int)sizeof_array(abbr_days); i++)
527  if (strncasecmp(abbr_days[i], RSTRING_PTR(s), 3) == 0)
528  break;
529  return i;
530 }
531 
532 static int
533 mon_num(VALUE s)
534 {
535  int i;
536 
537  for (i = 0; i < (int)sizeof_array(abbr_months); i++)
538  if (strncasecmp(abbr_months[i], RSTRING_PTR(s), 3) == 0)
539  break;
540  return i + 1;
541 }
542 
543 static int
544 parse_day_cb(VALUE m, VALUE hash)
545 {
546  VALUE s;
547 
548  s = rb_reg_nth_match(1, m);
549  set_hash("wday", INT2FIX(day_num(s)));
550  return 1;
551 }
552 
553 static int
554 parse_day(VALUE str, VALUE hash)
555 {
556  static const char pat_source[] =
557 #ifndef TIGHT_PARSER
558  "\\b(" ABBR_DAYS ")[^-/\\d\\s]*"
559 #else
560  "(" VALID_DAYS ")"
561 #endif
562  ;
563  static VALUE pat = Qnil;
564 
565  REGCOMP_I(pat);
566 #ifndef TIGHT_PARSER
567  SUBS(str, pat, parse_day_cb);
568 #else
569  SUBW(str, pat, parse_day_cb);
570 #endif
571 }
572 
573 static int
574 parse_time2_cb(VALUE m, VALUE hash)
575 {
576  VALUE h, min, s, f, p;
577 
578  h = rb_reg_nth_match(1, m);
579  h = str2num(h);
580 
581  min = rb_reg_nth_match(2, m);
582  if (!NIL_P(min))
583  min = str2num(min);
584 
585  s = rb_reg_nth_match(3, m);
586  if (!NIL_P(s))
587  s = str2num(s);
588 
589  f = rb_reg_nth_match(4, m);
590 
591  if (!NIL_P(f))
594 
595  p = rb_reg_nth_match(5, m);
596 
597  if (!NIL_P(p)) {
598  int ih = NUM2INT(h);
599  ih %= 12;
600  if (*RSTRING_PTR(p) == 'P' || *RSTRING_PTR(p) == 'p')
601  ih += 12;
602  h = INT2FIX(ih);
603  }
604 
605  set_hash("hour", h);
606  if (!NIL_P(min))
607  set_hash("min", min);
608  if (!NIL_P(s))
609  set_hash("sec", s);
610  if (!NIL_P(f))
611  set_hash("sec_fraction", f);
612 
613  return 1;
614 }
615 
616 static int
617 parse_time_cb(VALUE m, VALUE hash)
618 {
619  static const char pat_source[] =
620  "\\A(\\d+)h?"
621  "(?:\\s*:?\\s*(\\d+)m?"
622  "(?:"
623  "\\s*:?\\s*(\\d+)(?:[,.](\\d+))?s?"
624  ")?"
625  ")?"
626  "(?:\\s*([ap])(?:m\\b|\\.m\\.))?";
627  static VALUE pat = Qnil;
628  VALUE s1, s2;
629 
630  s1 = rb_reg_nth_match(1, m);
631  s2 = rb_reg_nth_match(2, m);
632 
633  if (!NIL_P(s2))
634  set_hash("zone", s2);
635 
636  REGCOMP_I(pat);
637 
638  {
639  VALUE m = f_match(pat, s1);
640 
641  if (NIL_P(m))
642  return 0;
643  parse_time2_cb(m, hash);
644  }
645 
646  return 1;
647 }
648 
649 static int
650 parse_time(VALUE str, VALUE hash)
651 {
652  static const char pat_source[] =
653  "("
654  "(?:"
655  "\\d+\\s*:\\s*\\d+"
656  "(?:"
657 #ifndef TIGHT_PARSER
658  "\\s*:\\s*\\d+(?:[,.]\\d*)?"
659 #else
660  "\\s*:\\s*\\d+(?:[,.]\\d+)?"
661 #endif
662  ")?"
663  "|"
664  "\\d+\\s*h(?:\\s*\\d+m?(?:\\s*\\d+s?)?)?"
665  ")"
666  "(?:"
667  "\\s*"
668  "[ap](?:m\\b|\\.m\\.)"
669  ")?"
670  "|"
671  "\\d+\\s*[ap](?:m\\b|\\.m\\.)"
672  ")"
673  "(?:"
674  "\\s*"
675  "("
676  "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?"
677  "|"
678  "(?-i:[[:alpha:].\\s]+)(?:standard|daylight)\\stime\\b"
679  "|"
680  "(?-i:[[:alpha:]]+)(?:\\sdst)?\\b"
681  ")"
682  ")?";
683  static VALUE pat = Qnil;
684 
685  REGCOMP_I(pat);
686 #ifndef TIGHT_PARSER
687  SUBS(str, pat, parse_time_cb);
688 #else
689  SUBT(str, pat, parse_time_cb);
690 #endif
691 }
692 
693 #ifdef TIGHT_PARSER
694 static int
695 parse_era1_cb(VALUE m, VALUE hash)
696 {
697  return 1;
698 }
699 
700 static int
701 parse_era1(VALUE str, VALUE hash)
702 {
703  static const char pat_source[] =
704  "(a(?:d|\\.d\\.))";
705  static VALUE pat = Qnil;
706 
707  REGCOMP_I(pat);
708  SUBA(str, pat, parse_era1_cb);
709 }
710 
711 static int
712 parse_era2_cb(VALUE m, VALUE hash)
713 {
714  VALUE b;
715 
716  b = rb_reg_nth_match(1, m);
717  if (*RSTRING_PTR(b) == 'B' ||
718  *RSTRING_PTR(b) == 'b')
719  set_hash("_bc", Qtrue);
720  return 1;
721 }
722 
723 static int
724 parse_era2(VALUE str, VALUE hash)
725 {
726  static const char pat_source[] =
727  "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|b(?:c|\\.c\\.))";
728  static VALUE pat = Qnil;
729 
730  REGCOMP_I(pat);
731  SUBB(str, pat, parse_era2_cb);
732 }
733 
734 static int
735 parse_era(VALUE str, VALUE hash)
736 {
737  if (parse_era1(str, hash)) /* pre */
738  goto ok;
739  if (parse_era2(str, hash)) /* post */
740  goto ok;
741  return 0;
742  ok:
743  return 1;
744 }
745 #endif
746 
747 #ifdef TIGHT_PARSER
748 static int
749 check_year_width(VALUE y)
750 {
751  const char *s;
752  long l;
753 
754  l = RSTRING_LEN(y);
755  if (l < 2) return 0;
756  s = RSTRING_PTR(y);
757  if (!isdigit(s[1])) return 0;
758  return (l == 2 || !isdigit(s[2]));
759 }
760 
761 static int
762 check_apost(VALUE a, VALUE b, VALUE c)
763 {
764  int f = 0;
765 
766  if (!NIL_P(a) && *RSTRING_PTR(a) == '\'') {
767  if (!check_year_width(a))
768  return 0;
769  f++;
770  }
771  if (!NIL_P(b) && *RSTRING_PTR(b) == '\'') {
772  if (!check_year_width(b))
773  return 0;
774  if (!NIL_P(c))
775  return 0;
776  f++;
777  }
778  if (!NIL_P(c) && *RSTRING_PTR(c) == '\'') {
779  if (!check_year_width(c))
780  return 0;
781  f++;
782  }
783  if (f > 1)
784  return 0;
785  return 1;
786 }
787 #endif
788 
789 static int
790 parse_eu_cb(VALUE m, VALUE hash)
791 {
792 #ifndef TIGHT_PARSER
793  VALUE y, mon, d, b;
794 
795  d = rb_reg_nth_match(1, m);
796  mon = rb_reg_nth_match(2, m);
797  b = rb_reg_nth_match(3, m);
798  y = rb_reg_nth_match(4, m);
799 
800  mon = INT2FIX(mon_num(mon));
801 
802  s3e(hash, y, mon, d, !NIL_P(b) &&
803  (*RSTRING_PTR(b) == 'B' ||
804  *RSTRING_PTR(b) == 'b'));
805 #else
806  VALUE y, mon, d;
807 
808  d = rb_reg_nth_match(1, m);
809  mon = rb_reg_nth_match(2, m);
810  y = rb_reg_nth_match(3, m);
811 
812  if (!check_apost(d, mon, y))
813  return 0;
814 
815  mon = INT2FIX(mon_num(mon));
816 
817  s3e(hash, y, mon, d, 0);
818 #endif
819  return 1;
820 }
821 
822 static int
823 parse_eu(VALUE str, VALUE hash)
824 {
825  static const char pat_source[] =
826 #ifdef TIGHT_PARSER
827  BOS
828  FPW_COM FPT_COM
829 #endif
830 #ifndef TIGHT_PARSER
831  "('?\\d+)[^-\\d\\s]*"
832 #else
833  "(\\d+)(?:(?:st|nd|rd|th)\\b)?"
834 #endif
835  "\\s*"
836 #ifndef TIGHT_PARSER
837  "(" ABBR_MONTHS ")[^-\\d\\s']*"
838 #else
839  "(" VALID_MONTHS ")"
840 #endif
841  "(?:"
842  "\\s*"
843 #ifndef TIGHT_PARSER
844  "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?"
845  "\\s*"
846  "('?-?\\d+(?:(?:st|nd|rd|th)\\b)?)"
847 #else
848  "(?:" FPA ")?"
849  "\\s*"
850  "([-']?\\d+)"
851  "\\s*"
852  "(?:" FPA "|" FPB ")?"
853 #endif
854  ")?"
855 #ifdef TIGHT_PARSER
856  COM_FPT COM_FPW
857  EOS
858 #endif
859  ;
860  static VALUE pat = Qnil;
861 
862  REGCOMP_I(pat);
863  SUBS(str, pat, parse_eu_cb);
864 }
865 
866 static int
867 parse_us_cb(VALUE m, VALUE hash)
868 {
869 #ifndef TIGHT_PARSER
870  VALUE y, mon, d, b;
871 
872  mon = rb_reg_nth_match(1, m);
873  d = rb_reg_nth_match(2, m);
874 
875  b = rb_reg_nth_match(3, m);
876  y = rb_reg_nth_match(4, m);
877 
878  mon = INT2FIX(mon_num(mon));
879 
880  s3e(hash, y, mon, d, !NIL_P(b) &&
881  (*RSTRING_PTR(b) == 'B' ||
882  *RSTRING_PTR(b) == 'b'));
883 #else
884  VALUE y, mon, d;
885 
886  mon = rb_reg_nth_match(1, m);
887  d = rb_reg_nth_match(2, m);
888  y = rb_reg_nth_match(3, m);
889 
890  if (!check_apost(mon, d, y))
891  return 0;
892 
893  mon = INT2FIX(mon_num(mon));
894 
895  s3e(hash, y, mon, d, 0);
896 #endif
897  return 1;
898 }
899 
900 static int
901 parse_us(VALUE str, VALUE hash)
902 {
903  static const char pat_source[] =
904 #ifdef TIGHT_PARSER
905  BOS
906  FPW_COM FPT_COM
907 #endif
908 #ifndef TIGHT_PARSER
909  "\\b(" ABBR_MONTHS ")[^-\\d\\s']*"
910 #else
911  "\\b(" VALID_MONTHS ")"
912 #endif
913  "\\s*"
914 #ifndef TIGHT_PARSER
915  "('?\\d+)[^-\\d\\s']*"
916 #else
917  "('?\\d+)(?:(?:st|nd|rd|th)\\b)?"
918  COM_FPT
919 #endif
920  "(?:"
921  "\\s*,?"
922  "\\s*"
923 #ifndef TIGHT_PARSER
924  "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?"
925  "\\s*"
926  "('?-?\\d+)"
927 #else
928  "(?:" FPA ")?"
929  "\\s*"
930  "([-']?\\d+)"
931  "\\s*"
932  "(?:" FPA "|" FPB ")?"
933 #endif
934  ")?"
935 #ifdef TIGHT_PARSER
936  COM_FPT COM_FPW
937  EOS
938 #endif
939  ;
940  static VALUE pat = Qnil;
941 
942  REGCOMP_I(pat);
943  SUBS(str, pat, parse_us_cb);
944 }
945 
946 static int
947 parse_iso_cb(VALUE m, VALUE hash)
948 {
949  VALUE y, mon, d;
950 
951  y = rb_reg_nth_match(1, m);
952  mon = rb_reg_nth_match(2, m);
953  d = rb_reg_nth_match(3, m);
954 
955 #ifdef TIGHT_PARSER
956  if (!check_apost(y, mon, d))
957  return 0;
958 #endif
959 
960  s3e(hash, y, mon, d, 0);
961  return 1;
962 }
963 
964 static int
965 parse_iso(VALUE str, VALUE hash)
966 {
967  static const char pat_source[] =
968 #ifndef TIGHT_PARSER
969  "('?[-+]?\\d+)-(\\d+)-('?-?\\d+)"
970 #else
971  BOS
972  FPW_COM FPT_COM
973  "([-+']?\\d+)-(\\d+)-([-']?\\d+)"
974  TEE_FPT COM_FPW
975  EOS
976 #endif
977  ;
978  static VALUE pat = Qnil;
979 
980  REGCOMP_0(pat);
981  SUBS(str, pat, parse_iso_cb);
982 }
983 
984 static int
985 parse_iso21_cb(VALUE m, VALUE hash)
986 {
987  VALUE y, w, d;
988 
989  y = rb_reg_nth_match(1, m);
990  w = rb_reg_nth_match(2, m);
991  d = rb_reg_nth_match(3, m);
992 
993  if (!NIL_P(y))
994  set_hash("cwyear", str2num(y));
995  set_hash("cweek", str2num(w));
996  if (!NIL_P(d))
997  set_hash("cwday", str2num(d));
998 
999  return 1;
1000 }
1001 
1002 static int
1003 parse_iso21(VALUE str, VALUE hash)
1004 {
1005  static const char pat_source[] =
1006 #ifndef TIGHT_PARSER
1007  "\\b(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?\\b"
1008 #else
1009  BOS
1010  FPW_COM FPT_COM
1011  "(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?"
1012  TEE_FPT COM_FPW
1013  EOS
1014 #endif
1015  ;
1016  static VALUE pat = Qnil;
1017 
1018  REGCOMP_I(pat);
1019  SUBS(str, pat, parse_iso21_cb);
1020 }
1021 
1022 static int
1023 parse_iso22_cb(VALUE m, VALUE hash)
1024 {
1025  VALUE d;
1026 
1027  d = rb_reg_nth_match(1, m);
1028  set_hash("cwday", str2num(d));
1029  return 1;
1030 }
1031 
1032 static int
1033 parse_iso22(VALUE str, VALUE hash)
1034 {
1035  static const char pat_source[] =
1036 #ifndef TIGHT_PARSER
1037  "-w-(\\d)\\b"
1038 #else
1039  BOS
1040  FPW_COM FPT_COM
1041  "-w-(\\d)"
1042  TEE_FPT COM_FPW
1043  EOS
1044 #endif
1045  ;
1046  static VALUE pat = Qnil;
1047 
1048  REGCOMP_I(pat);
1049  SUBS(str, pat, parse_iso22_cb);
1050 }
1051 
1052 static int
1053 parse_iso23_cb(VALUE m, VALUE hash)
1054 {
1055  VALUE mon, d;
1056 
1057  mon = rb_reg_nth_match(1, m);
1058  d = rb_reg_nth_match(2, m);
1059 
1060  if (!NIL_P(mon))
1061  set_hash("mon", str2num(mon));
1062  set_hash("mday", str2num(d));
1063 
1064  return 1;
1065 }
1066 
1067 static int
1068 parse_iso23(VALUE str, VALUE hash)
1069 {
1070  static const char pat_source[] =
1071 #ifndef TIGHT_PARSER
1072  "--(\\d{2})?-(\\d{2})\\b"
1073 #else
1074  BOS
1075  FPW_COM FPT_COM
1076  "--(\\d{2})?-(\\d{2})"
1077  TEE_FPT COM_FPW
1078  EOS
1079 #endif
1080  ;
1081  static VALUE pat = Qnil;
1082 
1083  REGCOMP_0(pat);
1084  SUBS(str, pat, parse_iso23_cb);
1085 }
1086 
1087 static int
1088 parse_iso24_cb(VALUE m, VALUE hash)
1089 {
1090  VALUE mon, d;
1091 
1092  mon = rb_reg_nth_match(1, m);
1093  d = rb_reg_nth_match(2, m);
1094 
1095  set_hash("mon", str2num(mon));
1096  if (!NIL_P(d))
1097  set_hash("mday", str2num(d));
1098 
1099  return 1;
1100 }
1101 
1102 static int
1103 parse_iso24(VALUE str, VALUE hash)
1104 {
1105  static const char pat_source[] =
1106 #ifndef TIGHT_PARSER
1107  "--(\\d{2})(\\d{2})?\\b"
1108 #else
1109  BOS
1110  FPW_COM FPT_COM
1111  "--(\\d{2})(\\d{2})?"
1112  TEE_FPT COM_FPW
1113  EOS
1114 #endif
1115  ;
1116  static VALUE pat = Qnil;
1117 
1118  REGCOMP_0(pat);
1119  SUBS(str, pat, parse_iso24_cb);
1120 }
1121 
1122 static int
1123 parse_iso25_cb(VALUE m, VALUE hash)
1124 {
1125  VALUE y, d;
1126 
1127  y = rb_reg_nth_match(1, m);
1128  d = rb_reg_nth_match(2, m);
1129 
1130  set_hash("year", str2num(y));
1131  set_hash("yday", str2num(d));
1132 
1133  return 1;
1134 }
1135 
1136 static int
1137 parse_iso25(VALUE str, VALUE hash)
1138 {
1139  static const char pat0_source[] =
1140 #ifndef TIGHT_PARSER
1141  "[,.](\\d{2}|\\d{4})-\\d{3}\\b"
1142 #else
1143  BOS
1144  FPW_COM FPT_COM
1145  "[,.](\\d{2}|\\d{4})-\\d{3}"
1146  TEE_FPT COM_FPW
1147  EOS
1148 #endif
1149  ;
1150  static VALUE pat0 = Qnil;
1151  static const char pat_source[] =
1152 #ifndef TIGHT_PARSER
1153  "\\b(\\d{2}|\\d{4})-(\\d{3})\\b"
1154 #else
1155  BOS
1156  FPW_COM FPT_COM
1157  "(\\d{2}|\\d{4})-(\\d{3})"
1158  TEE_FPT COM_FPW
1159  EOS
1160 #endif
1161  ;
1162  static VALUE pat = Qnil;
1163 
1164  REGCOMP_0(pat0);
1165  REGCOMP_0(pat);
1166 
1167  if (!NIL_P(f_match(pat0, str)))
1168  return 0;
1169  SUBS(str, pat, parse_iso25_cb);
1170 }
1171 
1172 static int
1173 parse_iso26_cb(VALUE m, VALUE hash)
1174 {
1175  VALUE d;
1176 
1177  d = rb_reg_nth_match(1, m);
1178  set_hash("yday", str2num(d));
1179 
1180  return 1;
1181 }
1182 static int
1183 parse_iso26(VALUE str, VALUE hash)
1184 {
1185  static const char pat0_source[] =
1186 #ifndef TIGHT_PARSER
1187  "\\d-\\d{3}\\b"
1188 #else
1189  BOS
1190  FPW_COM FPT_COM
1191  "\\d-\\d{3}"
1192  TEE_FPT COM_FPW
1193  EOS
1194 #endif
1195  ;
1196  static VALUE pat0 = Qnil;
1197  static const char pat_source[] =
1198 #ifndef TIGHT_PARSER
1199  "\\b-(\\d{3})\\b"
1200 #else
1201  BOS
1202  FPW_COM FPT_COM
1203  "-(\\d{3})"
1204  TEE_FPT COM_FPW
1205  EOS
1206 #endif
1207  ;
1208  static VALUE pat = Qnil;
1209 
1210  REGCOMP_0(pat0);
1211  REGCOMP_0(pat);
1212 
1213  if (!NIL_P(f_match(pat0, str)))
1214  return 0;
1215  SUBS(str, pat, parse_iso26_cb);
1216 }
1217 
1218 static int
1219 parse_iso2(VALUE str, VALUE hash)
1220 {
1221  if (parse_iso21(str, hash))
1222  goto ok;
1223  if (parse_iso22(str, hash))
1224  goto ok;
1225  if (parse_iso23(str, hash))
1226  goto ok;
1227  if (parse_iso24(str, hash))
1228  goto ok;
1229  if (parse_iso25(str, hash))
1230  goto ok;
1231  if (parse_iso26(str, hash))
1232  goto ok;
1233  return 0;
1234 
1235  ok:
1236  return 1;
1237 }
1238 
1239 #define JISX0301_ERA_INITIALS "mtshr"
1240 #define JISX0301_DEFAULT_ERA 'H' /* obsolete */
1241 
1242 static int
1243 gengo(int c)
1244 {
1245  int e;
1246 
1247  switch (c) {
1248  case 'M': case 'm': e = 1867; break;
1249  case 'T': case 't': e = 1911; break;
1250  case 'S': case 's': e = 1925; break;
1251  case 'H': case 'h': e = 1988; break;
1252  case 'R': case 'r': e = 2018; break;
1253  default: e = 0; break;
1254  }
1255  return e;
1256 }
1257 
1258 static int
1259 parse_jis_cb(VALUE m, VALUE hash)
1260 {
1261  VALUE e, y, mon, d;
1262  int ep;
1263 
1264  e = rb_reg_nth_match(1, m);
1265  y = rb_reg_nth_match(2, m);
1266  mon = rb_reg_nth_match(3, m);
1267  d = rb_reg_nth_match(4, m);
1268 
1269  ep = gengo(*RSTRING_PTR(e));
1270 
1271  set_hash("year", f_add(str2num(y), INT2FIX(ep)));
1272  set_hash("mon", str2num(mon));
1273  set_hash("mday", str2num(d));
1274 
1275  return 1;
1276 }
1277 
1278 static int
1279 parse_jis(VALUE str, VALUE hash)
1280 {
1281  static const char pat_source[] =
1282 #ifndef TIGHT_PARSER
1283  "\\b([" JISX0301_ERA_INITIALS "])(\\d+)\\.(\\d+)\\.(\\d+)"
1284 #else
1285  BOS
1286  FPW_COM FPT_COM
1287  "([" JISX0301_ERA_INITIALS "])(\\d+)\\.(\\d+)\\.(\\d+)"
1288  TEE_FPT COM_FPW
1289  EOS
1290 #endif
1291  ;
1292  static VALUE pat = Qnil;
1293 
1294  REGCOMP_I(pat);
1295  SUBS(str, pat, parse_jis_cb);
1296 }
1297 
1298 static int
1299 parse_vms11_cb(VALUE m, VALUE hash)
1300 {
1301  VALUE y, mon, d;
1302 
1303  d = rb_reg_nth_match(1, m);
1304  mon = rb_reg_nth_match(2, m);
1305  y = rb_reg_nth_match(3, m);
1306 
1307 #ifdef TIGHT_PARSER
1308  if (!check_apost(d, mon, y))
1309  return 0;
1310 #endif
1311 
1312  mon = INT2FIX(mon_num(mon));
1313 
1314  s3e(hash, y, mon, d, 0);
1315  return 1;
1316 }
1317 
1318 static int
1319 parse_vms11(VALUE str, VALUE hash)
1320 {
1321  static const char pat_source[] =
1322 #ifndef TIGHT_PARSER
1323  "('?-?\\d+)-(" ABBR_MONTHS ")[^-/.]*"
1324  "-('?-?\\d+)"
1325 #else
1326  BOS
1327  FPW_COM FPT_COM
1328  "([-']?\\d+)-(" DOTLESS_VALID_MONTHS ")"
1329  "-([-']?\\d+)"
1330  COM_FPT COM_FPW
1331  EOS
1332 #endif
1333  ;
1334  static VALUE pat = Qnil;
1335 
1336  REGCOMP_I(pat);
1337  SUBS(str, pat, parse_vms11_cb);
1338 }
1339 
1340 static int
1341 parse_vms12_cb(VALUE m, VALUE hash)
1342 {
1343  VALUE y, mon, d;
1344 
1345  mon = rb_reg_nth_match(1, m);
1346  d = rb_reg_nth_match(2, m);
1347  y = rb_reg_nth_match(3, m);
1348 
1349 #ifdef TIGHT_PARSER
1350  if (!check_apost(mon, d, y))
1351  return 0;
1352 #endif
1353 
1354  mon = INT2FIX(mon_num(mon));
1355 
1356  s3e(hash, y, mon, d, 0);
1357  return 1;
1358 }
1359 
1360 static int
1361 parse_vms12(VALUE str, VALUE hash)
1362 {
1363  static const char pat_source[] =
1364 #ifndef TIGHT_PARSER
1365  "\\b(" ABBR_MONTHS ")[^-/.]*"
1366  "-('?-?\\d+)(?:-('?-?\\d+))?"
1367 #else
1368  BOS
1369  FPW_COM FPT_COM
1370  "(" DOTLESS_VALID_MONTHS ")"
1371  "-([-']?\\d+)(?:-([-']?\\d+))?"
1372  COM_FPT COM_FPW
1373  EOS
1374 #endif
1375  ;
1376  static VALUE pat = Qnil;
1377 
1378  REGCOMP_I(pat);
1379  SUBS(str, pat, parse_vms12_cb);
1380 }
1381 
1382 static int
1383 parse_vms(VALUE str, VALUE hash)
1384 {
1385  if (parse_vms11(str, hash))
1386  goto ok;
1387  if (parse_vms12(str, hash))
1388  goto ok;
1389  return 0;
1390 
1391  ok:
1392  return 1;
1393 }
1394 
1395 static int
1396 parse_sla_cb(VALUE m, VALUE hash)
1397 {
1398  VALUE y, mon, d;
1399 
1400  y = rb_reg_nth_match(1, m);
1401  mon = rb_reg_nth_match(2, m);
1402  d = rb_reg_nth_match(3, m);
1403 
1404 #ifdef TIGHT_PARSER
1405  if (!check_apost(y, mon, d))
1406  return 0;
1407 #endif
1408 
1409  s3e(hash, y, mon, d, 0);
1410  return 1;
1411 }
1412 
1413 static int
1414 parse_sla(VALUE str, VALUE hash)
1415 {
1416  static const char pat_source[] =
1417 #ifndef TIGHT_PARSER
1418  "('?-?\\d+)/\\s*('?\\d+)(?:\\D\\s*('?-?\\d+))?"
1419 #else
1420  BOS
1421  FPW_COM FPT_COM
1422  "([-']?\\d+)/\\s*('?\\d+)(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?"
1423  COM_FPT COM_FPW
1424  EOS
1425 #endif
1426  ;
1427  static VALUE pat = Qnil;
1428 
1429  REGCOMP_I(pat);
1430  SUBS(str, pat, parse_sla_cb);
1431 }
1432 
1433 #ifdef TIGHT_PARSER
1434 static int
1435 parse_sla2_cb(VALUE m, VALUE hash)
1436 {
1437  VALUE y, mon, d;
1438 
1439  d = rb_reg_nth_match(1, m);
1440  mon = rb_reg_nth_match(2, m);
1441  y = rb_reg_nth_match(3, m);
1442 
1443  if (!check_apost(d, mon, y))
1444  return 0;
1445 
1446  mon = INT2FIX(mon_num(mon));
1447 
1448  s3e(hash, y, mon, d, 0);
1449  return 1;
1450 }
1451 
1452 static int
1453 parse_sla2(VALUE str, VALUE hash)
1454 {
1455  static const char pat_source[] =
1456  BOS
1457  FPW_COM FPT_COM
1458  "([-']?\\d+)/\\s*(" DOTLESS_VALID_MONTHS ")(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?"
1459  COM_FPT COM_FPW
1460  EOS
1461  ;
1462  static VALUE pat = Qnil;
1463 
1464  REGCOMP_I(pat);
1465  SUBS(str, pat, parse_sla2_cb);
1466 }
1467 
1468 static int
1469 parse_sla3_cb(VALUE m, VALUE hash)
1470 {
1471  VALUE y, mon, d;
1472 
1473  mon = rb_reg_nth_match(1, m);
1474  d = rb_reg_nth_match(2, m);
1475  y = rb_reg_nth_match(3, m);
1476 
1477  if (!check_apost(mon, d, y))
1478  return 0;
1479 
1480  mon = INT2FIX(mon_num(mon));
1481 
1482  s3e(hash, y, mon, d, 0);
1483  return 1;
1484 }
1485 
1486 static int
1487 parse_sla3(VALUE str, VALUE hash)
1488 {
1489  static const char pat_source[] =
1490  BOS
1491  FPW_COM FPT_COM
1492  "(" DOTLESS_VALID_MONTHS ")/\\s*([-']?\\d+)(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?"
1493  COM_FPT COM_FPW
1494  EOS
1495  ;
1496  static VALUE pat = Qnil;
1497 
1498  REGCOMP_I(pat);
1499  SUBS(str, pat, parse_sla3_cb);
1500 }
1501 #endif
1502 
1503 static int
1504 parse_dot_cb(VALUE m, VALUE hash)
1505 {
1506  VALUE y, mon, d;
1507 
1508  y = rb_reg_nth_match(1, m);
1509  mon = rb_reg_nth_match(2, m);
1510  d = rb_reg_nth_match(3, m);
1511 
1512 #ifdef TIGHT_PARSER
1513  if (!check_apost(y, mon, d))
1514  return 0;
1515 #endif
1516 
1517  s3e(hash, y, mon, d, 0);
1518  return 1;
1519 }
1520 
1521 static int
1522 parse_dot(VALUE str, VALUE hash)
1523 {
1524  static const char pat_source[] =
1525 #ifndef TIGHT_PARSER
1526  "('?-?\\d+)\\.\\s*('?\\d+)\\.\\s*('?-?\\d+)"
1527 #else
1528  BOS
1529  FPW_COM FPT_COM
1530  "([-']?\\d+)\\.\\s*(\\d+)\\.\\s*([-']?\\d+)"
1531  COM_FPT COM_FPW
1532  EOS
1533 #endif
1534  ;
1535  static VALUE pat = Qnil;
1536 
1537  REGCOMP_I(pat);
1538  SUBS(str, pat, parse_dot_cb);
1539 }
1540 
1541 #ifdef TIGHT_PARSER
1542 static int
1543 parse_dot2_cb(VALUE m, VALUE hash)
1544 {
1545  VALUE y, mon, d;
1546 
1547  d = rb_reg_nth_match(1, m);
1548  mon = rb_reg_nth_match(2, m);
1549  y = rb_reg_nth_match(3, m);
1550 
1551  if (!check_apost(d, mon, y))
1552  return 0;
1553 
1554  mon = INT2FIX(mon_num(mon));
1555 
1556  s3e(hash, y, mon, d, 0);
1557  return 1;
1558 }
1559 
1560 static int
1561 parse_dot2(VALUE str, VALUE hash)
1562 {
1563  static const char pat_source[] =
1564  BOS
1565  FPW_COM FPT_COM
1566  "([-']?\\d+)\\.\\s*(" DOTLESS_VALID_MONTHS ")(?:(?:[./])\\s*([-']?\\d+))?"
1567  COM_FPT COM_FPW
1568  EOS
1569  ;
1570  static VALUE pat = Qnil;
1571 
1572  REGCOMP_I(pat);
1573  SUBS(str, pat, parse_dot2_cb);
1574 }
1575 
1576 static int
1577 parse_dot3_cb(VALUE m, VALUE hash)
1578 {
1579  VALUE y, mon, d;
1580 
1581  mon = rb_reg_nth_match(1, m);
1582  d = rb_reg_nth_match(2, m);
1583  y = rb_reg_nth_match(3, m);
1584 
1585  if (!check_apost(mon, d, y))
1586  return 0;
1587 
1588  mon = INT2FIX(mon_num(mon));
1589 
1590  s3e(hash, y, mon, d, 0);
1591  return 1;
1592 }
1593 
1594 static int
1595 parse_dot3(VALUE str, VALUE hash)
1596 {
1597  static const char pat_source[] =
1598  BOS
1599  FPW_COM FPT_COM
1600  "(" DOTLESS_VALID_MONTHS ")\\.\\s*([-']?\\d+)(?:(?:[./])\\s*([-']?\\d+))?"
1601  COM_FPT COM_FPW
1602  EOS
1603  ;
1604  static VALUE pat = Qnil;
1605 
1606  REGCOMP_I(pat);
1607  SUBS(str, pat, parse_dot3_cb);
1608 }
1609 #endif
1610 
1611 static int
1612 parse_year_cb(VALUE m, VALUE hash)
1613 {
1614  VALUE y;
1615 
1616  y = rb_reg_nth_match(1, m);
1617  set_hash("year", str2num(y));
1618  return 1;
1619 }
1620 
1621 static int
1622 parse_year(VALUE str, VALUE hash)
1623 {
1624  static const char pat_source[] =
1625 #ifndef TIGHT_PARSER
1626  "'(\\d+)\\b"
1627 #else
1628  BOS
1629  FPW_COM FPT_COM
1630  "'(\\d+)"
1631  COM_FPT COM_FPW
1632  EOS
1633 #endif
1634  ;
1635  static VALUE pat = Qnil;
1636 
1637  REGCOMP_0(pat);
1638  SUBS(str, pat, parse_year_cb);
1639 }
1640 
1641 static int
1642 parse_mon_cb(VALUE m, VALUE hash)
1643 {
1644  VALUE mon;
1645 
1646  mon = rb_reg_nth_match(1, m);
1647  set_hash("mon", INT2FIX(mon_num(mon)));
1648  return 1;
1649 }
1650 
1651 static int
1652 parse_mon(VALUE str, VALUE hash)
1653 {
1654  static const char pat_source[] =
1655 #ifndef TIGHT_PARSER
1656  "\\b(" ABBR_MONTHS ")\\S*"
1657 #else
1658  BOS
1659  FPW_COM FPT_COM
1660  "(" VALID_MONTHS ")"
1661  COM_FPT COM_FPW
1662  EOS
1663 #endif
1664  ;
1665  static VALUE pat = Qnil;
1666 
1667  REGCOMP_I(pat);
1668  SUBS(str, pat, parse_mon_cb);
1669 }
1670 
1671 static int
1672 parse_mday_cb(VALUE m, VALUE hash)
1673 {
1674  VALUE d;
1675 
1676  d = rb_reg_nth_match(1, m);
1677  set_hash("mday", str2num(d));
1678  return 1;
1679 }
1680 
1681 static int
1682 parse_mday(VALUE str, VALUE hash)
1683 {
1684  static const char pat_source[] =
1685 #ifndef TIGHT_PARSER
1686  "(\\d+)(st|nd|rd|th)\\b"
1687 #else
1688  BOS
1689  FPW_COM FPT_COM
1690  "(\\d+)(st|nd|rd|th)"
1691  COM_FPT COM_FPW
1692  EOS
1693 #endif
1694  ;
1695  static VALUE pat = Qnil;
1696 
1697  REGCOMP_I(pat);
1698  SUBS(str, pat, parse_mday_cb);
1699 }
1700 
1701 static int
1702 n2i(const char *s, long f, long w)
1703 {
1704  long e, i;
1705  int v;
1706 
1707  e = f + w;
1708  v = 0;
1709  for (i = f; i < e; i++) {
1710  v *= 10;
1711  v += s[i] - '0';
1712  }
1713  return v;
1714 }
1715 
1716 static int
1717 parse_ddd_cb(VALUE m, VALUE hash)
1718 {
1719  VALUE s1, s2, s3, s4, s5;
1720  const char *cs2, *cs3, *cs5;
1721  long l2, l3, l4, l5;
1722 
1723  s1 = rb_reg_nth_match(1, m);
1724  s2 = rb_reg_nth_match(2, m);
1725  s3 = rb_reg_nth_match(3, m);
1726  s4 = rb_reg_nth_match(4, m);
1727  s5 = rb_reg_nth_match(5, m);
1728 
1729  cs2 = RSTRING_PTR(s2);
1730  l2 = RSTRING_LEN(s2);
1731 
1732  switch (l2) {
1733  case 2:
1734  if (NIL_P(s3) && !NIL_P(s4))
1735  set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2)));
1736  else
1737  set_hash("mday", INT2FIX(n2i(cs2, 0, 2)));
1738  break;
1739  case 4:
1740  if (NIL_P(s3) && !NIL_P(s4)) {
1741  set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2)));
1742  set_hash("min", INT2FIX(n2i(cs2, l2-4, 2)));
1743  }
1744  else {
1745  set_hash("mon", INT2FIX(n2i(cs2, 0, 2)));
1746  set_hash("mday", INT2FIX(n2i(cs2, 2, 2)));
1747  }
1748  break;
1749  case 6:
1750  if (NIL_P(s3) && !NIL_P(s4)) {
1751  set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2)));
1752  set_hash("min", INT2FIX(n2i(cs2, l2-4, 2)));
1753  set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
1754  }
1755  else {
1756  int y = n2i(cs2, 0, 2);
1757  if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
1758  y = -y;
1759  set_hash("year", INT2FIX(y));
1760  set_hash("mon", INT2FIX(n2i(cs2, 2, 2)));
1761  set_hash("mday", INT2FIX(n2i(cs2, 4, 2)));
1762  }
1763  break;
1764  case 8:
1765  case 10:
1766  case 12:
1767  case 14:
1768  if (NIL_P(s3) && !NIL_P(s4)) {
1769  set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2)));
1770  set_hash("min", INT2FIX(n2i(cs2, l2-4, 2)));
1771  set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
1772  set_hash("mday", INT2FIX(n2i(cs2, l2-8, 2)));
1773  if (l2 >= 10)
1774  set_hash("mon", INT2FIX(n2i(cs2, l2-10, 2)));
1775  if (l2 == 12) {
1776  int y = n2i(cs2, l2-12, 2);
1777  if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
1778  y = -y;
1779  set_hash("year", INT2FIX(y));
1780  }
1781  if (l2 == 14) {
1782  int y = n2i(cs2, l2-14, 4);
1783  if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
1784  y = -y;
1785  set_hash("year", INT2FIX(y));
1786  set_hash("_comp", Qfalse);
1787  }
1788  }
1789  else {
1790  int y = n2i(cs2, 0, 4);
1791  if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
1792  y = -y;
1793  set_hash("year", INT2FIX(y));
1794  set_hash("mon", INT2FIX(n2i(cs2, 4, 2)));
1795  set_hash("mday", INT2FIX(n2i(cs2, 6, 2)));
1796  if (l2 >= 10)
1797  set_hash("hour", INT2FIX(n2i(cs2, 8, 2)));
1798  if (l2 >= 12)
1799  set_hash("min", INT2FIX(n2i(cs2, 10, 2)));
1800  if (l2 >= 14)
1801  set_hash("sec", INT2FIX(n2i(cs2, 12, 2)));
1802  set_hash("_comp", Qfalse);
1803  }
1804  break;
1805  case 3:
1806  if (NIL_P(s3) && !NIL_P(s4)) {
1807  set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2)));
1808  set_hash("min", INT2FIX(n2i(cs2, l2-3, 1)));
1809  }
1810  else
1811  set_hash("yday", INT2FIX(n2i(cs2, 0, 3)));
1812  break;
1813  case 5:
1814  if (NIL_P(s3) && !NIL_P(s4)) {
1815  set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2)));
1816  set_hash("min", INT2FIX(n2i(cs2, l2-4, 2)));
1817  set_hash("hour", INT2FIX(n2i(cs2, l2-5, 1)));
1818  }
1819  else {
1820  int y = n2i(cs2, 0, 2);
1821  if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
1822  y = -y;
1823  set_hash("year", INT2FIX(y));
1824  set_hash("yday", INT2FIX(n2i(cs2, 2, 3)));
1825  }
1826  break;
1827  case 7:
1828  if (NIL_P(s3) && !NIL_P(s4)) {
1829  set_hash("sec", INT2FIX(n2i(cs2, l2-2, 2)));
1830  set_hash("min", INT2FIX(n2i(cs2, l2-4, 2)));
1831  set_hash("hour", INT2FIX(n2i(cs2, l2-6, 2)));
1832  set_hash("mday", INT2FIX(n2i(cs2, l2-7, 1)));
1833  }
1834  else {
1835  int y = n2i(cs2, 0, 4);
1836  if (!NIL_P(s1) && *RSTRING_PTR(s1) == '-')
1837  y = -y;
1838  set_hash("year", INT2FIX(y));
1839  set_hash("yday", INT2FIX(n2i(cs2, 4, 3)));
1840  }
1841  break;
1842  }
1843  RB_GC_GUARD(s2);
1844  if (!NIL_P(s3)) {
1845  cs3 = RSTRING_PTR(s3);
1846  l3 = RSTRING_LEN(s3);
1847 
1848  if (!NIL_P(s4)) {
1849  switch (l3) {
1850  case 2:
1851  case 4:
1852  case 6:
1853  set_hash("sec", INT2FIX(n2i(cs3, l3-2, 2)));
1854  if (l3 >= 4)
1855  set_hash("min", INT2FIX(n2i(cs3, l3-4, 2)));
1856  if (l3 >= 6)
1857  set_hash("hour", INT2FIX(n2i(cs3, l3-6, 2)));
1858  break;
1859  }
1860  }
1861  else {
1862  switch (l3) {
1863  case 2:
1864  case 4:
1865  case 6:
1866  set_hash("hour", INT2FIX(n2i(cs3, 0, 2)));
1867  if (l3 >= 4)
1868  set_hash("min", INT2FIX(n2i(cs3, 2, 2)));
1869  if (l3 >= 6)
1870  set_hash("sec", INT2FIX(n2i(cs3, 4, 2)));
1871  break;
1872  }
1873  }
1874  RB_GC_GUARD(s3);
1875  }
1876  if (!NIL_P(s4)) {
1877  l4 = RSTRING_LEN(s4);
1878 
1879  set_hash("sec_fraction",
1881  f_expt(INT2FIX(10), LONG2NUM(l4))));
1882  }
1883  if (!NIL_P(s5)) {
1884  cs5 = RSTRING_PTR(s5);
1885  l5 = RSTRING_LEN(s5);
1886 
1887  set_hash("zone", s5);
1888 
1889  if (*cs5 == '[') {
1890  const char *s1, *s2;
1891  VALUE zone;
1892 
1893  l5 -= 2;
1894  s1 = cs5 + 1;
1895  s2 = memchr(s1, ':', l5);
1896  if (s2) {
1897  s2++;
1898  zone = rb_str_subseq(s5, s2 - cs5, l5 - (s2 - s1));
1899  s5 = rb_str_subseq(s5, 1, s2 - s1);
1900  }
1901  else {
1902  zone = rb_str_subseq(s5, 1, l5);
1903  if (isdigit((unsigned char)*s1))
1904  s5 = rb_str_append(rb_str_new_cstr("+"), zone);
1905  else
1906  s5 = zone;
1907  }
1908  set_hash("zone", zone);
1909  set_hash("offset", date_zone_to_diff(s5));
1910  }
1911  RB_GC_GUARD(s5);
1912  }
1913 
1914  return 1;
1915 }
1916 
1917 static int
1918 parse_ddd(VALUE str, VALUE hash)
1919 {
1920  static const char pat_source[] =
1921 #ifdef TIGHT_PARSER
1922  BOS
1923 #endif
1924  "([-+]?)(\\d{2,14})"
1925  "(?:"
1926  "\\s*"
1927  "t?"
1928  "\\s*"
1929  "(\\d{2,6})?(?:[,.](\\d*))?"
1930  ")?"
1931  "(?:"
1932  "\\s*"
1933  "("
1934  "z\\b"
1935  "|"
1936  "[-+]\\d{1,4}\\b"
1937  "|"
1938  "\\[[-+]?\\d[^\\]]*\\]"
1939  ")"
1940  ")?"
1941 #ifdef TIGHT_PARSER
1942  EOS
1943 #endif
1944  ;
1945  static VALUE pat = Qnil;
1946 
1947  REGCOMP_I(pat);
1948  SUBS(str, pat, parse_ddd_cb);
1949 }
1950 
1951 #ifndef TIGHT_PARSER
1952 static int
1953 parse_bc_cb(VALUE m, VALUE hash)
1954 {
1955  set_hash("_bc", Qtrue);
1956  return 1;
1957 }
1958 
1959 static int
1960 parse_bc(VALUE str, VALUE hash)
1961 {
1962  static const char pat_source[] =
1963  "\\b(bc\\b|bce\\b|b\\.c\\.|b\\.c\\.e\\.)";
1964  static VALUE pat = Qnil;
1965 
1966  REGCOMP_I(pat);
1967  SUBS(str, pat, parse_bc_cb);
1968 }
1969 
1970 static int
1971 parse_frag_cb(VALUE m, VALUE hash)
1972 {
1973  VALUE s, n;
1974 
1975  s = rb_reg_nth_match(1, m);
1976 
1977  if (!NIL_P(ref_hash("hour")) && NIL_P(ref_hash("mday"))) {
1978  n = str2num(s);
1979  if (f_ge_p(n, INT2FIX(1)) &&
1980  f_le_p(n, INT2FIX(31)))
1981  set_hash("mday", n);
1982  }
1983  if (!NIL_P(ref_hash("mday")) && NIL_P(ref_hash("hour"))) {
1984  n = str2num(s);
1985  if (f_ge_p(n, INT2FIX(0)) &&
1986  f_le_p(n, INT2FIX(24)))
1987  set_hash("hour", n);
1988  }
1989 
1990  return 1;
1991 }
1992 
1993 static int
1994 parse_frag(VALUE str, VALUE hash)
1995 {
1996  static const char pat_source[] = "\\A\\s*(\\d{1,2})\\s*\\z";
1997  static VALUE pat = Qnil;
1998 
1999  REGCOMP_I(pat);
2000  SUBS(str, pat, parse_frag_cb);
2001 }
2002 #endif
2003 
2004 #ifdef TIGHT_PARSER
2005 static int
2006 parse_dummy_cb(VALUE m, VALUE hash)
2007 {
2008  return 1;
2009 }
2010 
2011 static int
2012 parse_wday_only(VALUE str, VALUE hash)
2013 {
2014  static const char pat_source[] = "\\A\\s*" FPW "\\s*\\z";
2015  static VALUE pat = Qnil;
2016 
2017  REGCOMP_0(pat);
2018  SUBS(str, pat, parse_dummy_cb);
2019 }
2020 
2021 static int
2022 parse_time_only(VALUE str, VALUE hash)
2023 {
2024  static const char pat_source[] = "\\A\\s*" FPT "\\s*\\z";
2025  static VALUE pat = Qnil;
2026 
2027  REGCOMP_0(pat);
2028  SUBS(str, pat, parse_dummy_cb);
2029 }
2030 
2031 static int
2032 parse_wday_and_time(VALUE str, VALUE hash)
2033 {
2034  static const char pat_source[] = "\\A\\s*(" FPW "\\s+" FPT "|" FPT "\\s+" FPW ")\\s*\\z";
2035  static VALUE pat = Qnil;
2036 
2037  REGCOMP_0(pat);
2038  SUBS(str, pat, parse_dummy_cb);
2039 }
2040 
2041 static unsigned
2042 have_invalid_char_p(VALUE s)
2043 {
2044  long i;
2045 
2046  for (i = 0; i < RSTRING_LEN(s); i++)
2047  if (iscntrl((unsigned char)RSTRING_PTR(s)[i]) &&
2048  !isspace((unsigned char)RSTRING_PTR(s)[i]))
2049  return 1;
2050  return 0;
2051 }
2052 #endif
2053 
2054 #define HAVE_ALPHA (1<<0)
2055 #define HAVE_DIGIT (1<<1)
2056 #define HAVE_DASH (1<<2)
2057 #define HAVE_DOT (1<<3)
2058 #define HAVE_SLASH (1<<4)
2059 
2060 static unsigned
2061 check_class(VALUE s)
2062 {
2063  unsigned flags;
2064  long i;
2065 
2066  flags = 0;
2067  for (i = 0; i < RSTRING_LEN(s); i++) {
2068  if (isalpha((unsigned char)RSTRING_PTR(s)[i]))
2069  flags |= HAVE_ALPHA;
2070  if (isdigit((unsigned char)RSTRING_PTR(s)[i]))
2071  flags |= HAVE_DIGIT;
2072  if (RSTRING_PTR(s)[i] == '-')
2073  flags |= HAVE_DASH;
2074  if (RSTRING_PTR(s)[i] == '.')
2075  flags |= HAVE_DOT;
2076  if (RSTRING_PTR(s)[i] == '/')
2077  flags |= HAVE_SLASH;
2078  }
2079  return flags;
2080 }
2081 
2082 #define HAVE_ELEM_P(x) ((check_class(str) & (x)) == (x))
2083 
2084 #ifdef TIGHT_PARSER
2085 #define PARSER_ERROR return rb_hash_new()
2086 #endif
2087 
2088 VALUE
2089 date__parse(VALUE str, VALUE comp)
2090 {
2091  VALUE backref, hash;
2092 
2093 #ifdef TIGHT_PARSER
2094  if (have_invalid_char_p(str))
2095  PARSER_ERROR;
2096 #endif
2097 
2098  backref = rb_backref_get();
2099  rb_match_busy(backref);
2100 
2101  {
2102  static const char pat_source[] =
2103 #ifndef TIGHT_PARSER
2104  "[^-+',./:@[:alnum:]\\[\\]]+"
2105 #else
2106  "[^[:graph:]]+"
2107 #endif
2108  ;
2109  static VALUE pat = Qnil;
2110 
2111  REGCOMP_0(pat);
2112  str = rb_str_dup(str);
2113  f_gsub_bang(str, pat, asp_string());
2114  }
2115 
2116  hash = rb_hash_new();
2117  set_hash("_comp", comp);
2118 
2119  if (HAVE_ELEM_P(HAVE_ALPHA))
2120  parse_day(str, hash);
2121  if (HAVE_ELEM_P(HAVE_DIGIT))
2122  parse_time(str, hash);
2123 
2124 #ifdef TIGHT_PARSER
2125  if (HAVE_ELEM_P(HAVE_ALPHA))
2126  parse_era(str, hash);
2127 #endif
2128 
2130  if (parse_eu(str, hash))
2131  goto ok;
2132  if (parse_us(str, hash))
2133  goto ok;
2134  }
2136  if (parse_iso(str, hash))
2137  goto ok;
2139  if (parse_jis(str, hash))
2140  goto ok;
2142  if (parse_vms(str, hash))
2143  goto ok;
2145  if (parse_sla(str, hash))
2146  goto ok;
2147 #ifdef TIGHT_PARSER
2149  if (parse_sla2(str, hash))
2150  goto ok;
2151  if (parse_sla3(str, hash))
2152  goto ok;
2153  }
2154 #endif
2156  if (parse_dot(str, hash))
2157  goto ok;
2158 #ifdef TIGHT_PARSER
2160  if (parse_dot2(str, hash))
2161  goto ok;
2162  if (parse_dot3(str, hash))
2163  goto ok;
2164  }
2165 #endif
2166  if (HAVE_ELEM_P(HAVE_DIGIT))
2167  if (parse_iso2(str, hash))
2168  goto ok;
2169  if (HAVE_ELEM_P(HAVE_DIGIT))
2170  if (parse_year(str, hash))
2171  goto ok;
2172  if (HAVE_ELEM_P(HAVE_ALPHA))
2173  if (parse_mon(str, hash))
2174  goto ok;
2175  if (HAVE_ELEM_P(HAVE_DIGIT))
2176  if (parse_mday(str, hash))
2177  goto ok;
2178  if (HAVE_ELEM_P(HAVE_DIGIT))
2179  if (parse_ddd(str, hash))
2180  goto ok;
2181 
2182 #ifdef TIGHT_PARSER
2183  if (parse_wday_only(str, hash))
2184  goto ok;
2185  if (parse_time_only(str, hash))
2186  goto ok;
2187  if (parse_wday_and_time(str, hash))
2188  goto ok;
2189 
2190  PARSER_ERROR; /* not found */
2191 #endif
2192 
2193  ok:
2194 #ifndef TIGHT_PARSER
2195  if (HAVE_ELEM_P(HAVE_ALPHA))
2196  parse_bc(str, hash);
2197  if (HAVE_ELEM_P(HAVE_DIGIT))
2198  parse_frag(str, hash);
2199 #endif
2200 
2201  {
2202  if (RTEST(del_hash("_bc"))) {
2203  VALUE y;
2204 
2205  y = ref_hash("cwyear");
2206  if (!NIL_P(y)) {
2207  y = f_add(f_negate(y), INT2FIX(1));
2208  set_hash("cwyear", y);
2209  }
2210  y = ref_hash("year");
2211  if (!NIL_P(y)) {
2212  y = f_add(f_negate(y), INT2FIX(1));
2213  set_hash("year", y);
2214  }
2215  }
2216 
2217  if (RTEST(del_hash("_comp"))) {
2218  VALUE y;
2219 
2220  y = ref_hash("cwyear");
2221  if (!NIL_P(y))
2222  if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) {
2223  if (f_ge_p(y, INT2FIX(69)))
2224  set_hash("cwyear", f_add(y, INT2FIX(1900)));
2225  else
2226  set_hash("cwyear", f_add(y, INT2FIX(2000)));
2227  }
2228  y = ref_hash("year");
2229  if (!NIL_P(y))
2230  if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99))) {
2231  if (f_ge_p(y, INT2FIX(69)))
2232  set_hash("year", f_add(y, INT2FIX(1900)));
2233  else
2234  set_hash("year", f_add(y, INT2FIX(2000)));
2235  }
2236  }
2237 
2238  }
2239 
2240  {
2241  VALUE zone = ref_hash("zone");
2242  if (!NIL_P(zone) && NIL_P(ref_hash("offset")))
2243  set_hash("offset", date_zone_to_diff(zone));
2244  }
2245 
2246  rb_backref_set(backref);
2247 
2248  return hash;
2249 }
2250 
2251 static VALUE
2252 comp_year69(VALUE y)
2253 {
2254  if (f_ge_p(y, INT2FIX(69)))
2255  return f_add(y, INT2FIX(1900));
2256  return f_add(y, INT2FIX(2000));
2257 }
2258 
2259 static VALUE
2260 comp_year50(VALUE y)
2261 {
2262  if (f_ge_p(y, INT2FIX(50)))
2263  return f_add(y, INT2FIX(1900));
2264  return f_add(y, INT2FIX(2000));
2265 }
2266 
2267 static VALUE
2268 sec_fraction(VALUE f)
2269 {
2270  return rb_rational_new2(str2num(f),
2271  f_expt(INT2FIX(10),
2272  LONG2NUM(RSTRING_LEN(f))));
2273 }
2274 
2275 #define SNUM 14
2276 
2277 static int
2278 iso8601_ext_datetime_cb(VALUE m, VALUE hash)
2279 {
2280  VALUE s[SNUM + 1], y;
2281 
2282  {
2283  int i;
2284  s[0] = Qnil;
2285  for (i = 1; i <= SNUM; i++)
2286  s[i] = rb_reg_nth_match(i, m);
2287  }
2288 
2289  if (!NIL_P(s[1])) {
2290  if (!NIL_P(s[3])) set_hash("mday", str2num(s[3]));
2291  if (strcmp(RSTRING_PTR(s[1]), "-") != 0) {
2292  y = str2num(s[1]);
2293  if (RSTRING_LEN(s[1]) < 4)
2294  y = comp_year69(y);
2295  set_hash("year", y);
2296  }
2297  if (NIL_P(s[2])) {
2298  if (strcmp(RSTRING_PTR(s[1]), "-") != 0)
2299  return 0;
2300  }
2301  else
2302  set_hash("mon", str2num(s[2]));
2303  }
2304  else if (!NIL_P(s[5])) {
2305  set_hash("yday", str2num(s[5]));
2306  if (!NIL_P(s[4])) {
2307  y = str2num(s[4]);
2308  if (RSTRING_LEN(s[4]) < 4)
2309  y = comp_year69(y);
2310  set_hash("year", y);
2311  }
2312  }
2313  else if (!NIL_P(s[8])) {
2314  set_hash("cweek", str2num(s[7]));
2315  set_hash("cwday", str2num(s[8]));
2316  if (!NIL_P(s[6])) {
2317  y = str2num(s[6]);
2318  if (RSTRING_LEN(s[6]) < 4)
2319  y = comp_year69(y);
2320  set_hash("cwyear", y);
2321  }
2322  }
2323  else if (!NIL_P(s[9])) {
2324  set_hash("cwday", str2num(s[9]));
2325  }
2326  if (!NIL_P(s[10])) {
2327  set_hash("hour", str2num(s[10]));
2328  set_hash("min", str2num(s[11]));
2329  if (!NIL_P(s[12]))
2330  set_hash("sec", str2num(s[12]));
2331  }
2332  if (!NIL_P(s[13])) {
2333  set_hash("sec_fraction", sec_fraction(s[13]));
2334  }
2335  if (!NIL_P(s[14])) {
2336  set_hash("zone", s[14]);
2337  set_hash("offset", date_zone_to_diff(s[14]));
2338  }
2339 
2340  return 1;
2341 }
2342 
2343 static int
2344 iso8601_ext_datetime(VALUE str, VALUE hash)
2345 {
2346  static const char pat_source[] =
2347  "\\A\\s*(?:([-+]?\\d{2,}|-)-(\\d{2})?(?:-(\\d{2}))?|"
2348  "([-+]?\\d{2,})?-(\\d{3})|"
2349  "(\\d{4}|\\d{2})?-w(\\d{2})-(\\d)|"
2350  "-w-(\\d))"
2351  "(?:t"
2352  "(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?)?"
2353  "(z|[-+]\\d{2}(?::?\\d{2})?)?)?\\s*\\z";
2354  static VALUE pat = Qnil;
2355 
2356  REGCOMP_I(pat);
2357  MATCH(str, pat, iso8601_ext_datetime_cb);
2358 }
2359 
2360 #undef SNUM
2361 #define SNUM 17
2362 
2363 static int
2364 iso8601_bas_datetime_cb(VALUE m, VALUE hash)
2365 {
2366  VALUE s[SNUM + 1], y;
2367 
2368  {
2369  int i;
2370  s[0] = Qnil;
2371  for (i = 1; i <= SNUM; i++)
2372  s[i] = rb_reg_nth_match(i, m);
2373  }
2374 
2375  if (!NIL_P(s[3])) {
2376  set_hash("mday", str2num(s[3]));
2377  if (strcmp(RSTRING_PTR(s[1]), "--") != 0) {
2378  y = str2num(s[1]);
2379  if (RSTRING_LEN(s[1]) < 4)
2380  y = comp_year69(y);
2381  set_hash("year", y);
2382  }
2383  if (*RSTRING_PTR(s[2]) == '-') {
2384  if (strcmp(RSTRING_PTR(s[1]), "--") != 0)
2385  return 0;
2386  }
2387  else
2388  set_hash("mon", str2num(s[2]));
2389  }
2390  else if (!NIL_P(s[5])) {
2391  set_hash("yday", str2num(s[5]));
2392  y = str2num(s[4]);
2393  if (RSTRING_LEN(s[4]) < 4)
2394  y = comp_year69(y);
2395  set_hash("year", y);
2396  }
2397  else if (!NIL_P(s[6])) {
2398  set_hash("yday", str2num(s[6]));
2399  }
2400  else if (!NIL_P(s[9])) {
2401  set_hash("cweek", str2num(s[8]));
2402  set_hash("cwday", str2num(s[9]));
2403  y = str2num(s[7]);
2404  if (RSTRING_LEN(s[7]) < 4)
2405  y = comp_year69(y);
2406  set_hash("cwyear", y);
2407  }
2408  else if (!NIL_P(s[11])) {
2409  set_hash("cweek", str2num(s[10]));
2410  set_hash("cwday", str2num(s[11]));
2411  }
2412  else if (!NIL_P(s[12])) {
2413  set_hash("cwday", str2num(s[12]));
2414  }
2415  if (!NIL_P(s[13])) {
2416  set_hash("hour", str2num(s[13]));
2417  set_hash("min", str2num(s[14]));
2418  if (!NIL_P(s[15]))
2419  set_hash("sec", str2num(s[15]));
2420  }
2421  if (!NIL_P(s[16])) {
2422  set_hash("sec_fraction", sec_fraction(s[16]));
2423  }
2424  if (!NIL_P(s[17])) {
2425  set_hash("zone", s[17]);
2426  set_hash("offset", date_zone_to_diff(s[17]));
2427  }
2428 
2429  return 1;
2430 }
2431 
2432 static int
2433 iso8601_bas_datetime(VALUE str, VALUE hash)
2434 {
2435  static const char pat_source[] =
2436  "\\A\\s*(?:([-+]?(?:\\d{4}|\\d{2})|--)(\\d{2}|-)(\\d{2})|"
2437  "([-+]?(?:\\d{4}|\\d{2}))(\\d{3})|"
2438  "-(\\d{3})|"
2439  "(\\d{4}|\\d{2})w(\\d{2})(\\d)|"
2440  "-w(\\d{2})(\\d)|"
2441  "-w-(\\d))"
2442  "(?:t?"
2443  "(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?)?"
2444  "(z|[-+]\\d{2}(?:\\d{2})?)?)?\\s*\\z";
2445  static VALUE pat = Qnil;
2446 
2447  REGCOMP_I(pat);
2448  MATCH(str, pat, iso8601_bas_datetime_cb);
2449 }
2450 
2451 #undef SNUM
2452 #define SNUM 5
2453 
2454 static int
2455 iso8601_ext_time_cb(VALUE m, VALUE hash)
2456 {
2457  VALUE s[SNUM + 1];
2458 
2459  {
2460  int i;
2461  s[0] = Qnil;
2462  for (i = 1; i <= SNUM; i++)
2463  s[i] = rb_reg_nth_match(i, m);
2464  }
2465 
2466  set_hash("hour", str2num(s[1]));
2467  set_hash("min", str2num(s[2]));
2468  if (!NIL_P(s[3]))
2469  set_hash("sec", str2num(s[3]));
2470  if (!NIL_P(s[4]))
2471  set_hash("sec_fraction", sec_fraction(s[4]));
2472  if (!NIL_P(s[5])) {
2473  set_hash("zone", s[5]);
2474  set_hash("offset", date_zone_to_diff(s[5]));
2475  }
2476 
2477  return 1;
2478 }
2479 
2480 #define iso8601_bas_time_cb iso8601_ext_time_cb
2481 
2482 static int
2483 iso8601_ext_time(VALUE str, VALUE hash)
2484 {
2485  static const char pat_source[] =
2486  "\\A\\s*(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?"
2487  "(z|[-+]\\d{2}(:?\\d{2})?)?)?\\s*\\z";
2488  static VALUE pat = Qnil;
2489 
2490  REGCOMP_I(pat);
2491  MATCH(str, pat, iso8601_ext_time_cb);
2492 }
2493 
2494 static int
2495 iso8601_bas_time(VALUE str, VALUE hash)
2496 {
2497  static const char pat_source[] =
2498  "\\A\\s*(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?"
2499  "(z|[-+]\\d{2}(\\d{2})?)?)?\\s*\\z";
2500  static VALUE pat = Qnil;
2501 
2502  REGCOMP_I(pat);
2503  MATCH(str, pat, iso8601_bas_time_cb);
2504 }
2505 
2506 VALUE
2508 {
2509  VALUE backref, hash;
2510 
2511  backref = rb_backref_get();
2512  rb_match_busy(backref);
2513 
2514  hash = rb_hash_new();
2515 
2516  if (iso8601_ext_datetime(str, hash))
2517  goto ok;
2518  if (iso8601_bas_datetime(str, hash))
2519  goto ok;
2520  if (iso8601_ext_time(str, hash))
2521  goto ok;
2522  if (iso8601_bas_time(str, hash))
2523  goto ok;
2524 
2525  ok:
2526  rb_backref_set(backref);
2527 
2528  return hash;
2529 }
2530 
2531 #undef SNUM
2532 #define SNUM 8
2533 
2534 static int
2535 rfc3339_cb(VALUE m, VALUE hash)
2536 {
2537  VALUE s[SNUM + 1];
2538 
2539  {
2540  int i;
2541  s[0] = Qnil;
2542  for (i = 1; i <= SNUM; i++)
2543  s[i] = rb_reg_nth_match(i, m);
2544  }
2545 
2546  set_hash("year", str2num(s[1]));
2547  set_hash("mon", str2num(s[2]));
2548  set_hash("mday", str2num(s[3]));
2549  set_hash("hour", str2num(s[4]));
2550  set_hash("min", str2num(s[5]));
2551  set_hash("sec", str2num(s[6]));
2552  set_hash("zone", s[8]);
2553  set_hash("offset", date_zone_to_diff(s[8]));
2554  if (!NIL_P(s[7]))
2555  set_hash("sec_fraction", sec_fraction(s[7]));
2556 
2557  return 1;
2558 }
2559 
2560 static int
2561 rfc3339(VALUE str, VALUE hash)
2562 {
2563  static const char pat_source[] =
2564  "\\A\\s*(-?\\d{4})-(\\d{2})-(\\d{2})"
2565  "(?:t|\\s)"
2566  "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?"
2567  "(z|[-+]\\d{2}:\\d{2})\\s*\\z";
2568  static VALUE pat = Qnil;
2569 
2570  REGCOMP_I(pat);
2571  MATCH(str, pat, rfc3339_cb);
2572 }
2573 
2574 VALUE
2576 {
2577  VALUE backref, hash;
2578 
2579  backref = rb_backref_get();
2580  rb_match_busy(backref);
2581 
2582  hash = rb_hash_new();
2583  rfc3339(str, hash);
2584  rb_backref_set(backref);
2585  return hash;
2586 }
2587 
2588 #undef SNUM
2589 #define SNUM 8
2590 
2591 static int
2592 xmlschema_datetime_cb(VALUE m, VALUE hash)
2593 {
2594  VALUE s[SNUM + 1];
2595 
2596  {
2597  int i;
2598  s[0] = Qnil;
2599  for (i = 1; i <= SNUM; i++)
2600  s[i] = rb_reg_nth_match(i, m);
2601  }
2602 
2603  set_hash("year", str2num(s[1]));
2604  if (!NIL_P(s[2]))
2605  set_hash("mon", str2num(s[2]));
2606  if (!NIL_P(s[3]))
2607  set_hash("mday", str2num(s[3]));
2608  if (!NIL_P(s[4]))
2609  set_hash("hour", str2num(s[4]));
2610  if (!NIL_P(s[5]))
2611  set_hash("min", str2num(s[5]));
2612  if (!NIL_P(s[6]))
2613  set_hash("sec", str2num(s[6]));
2614  if (!NIL_P(s[7]))
2615  set_hash("sec_fraction", sec_fraction(s[7]));
2616  if (!NIL_P(s[8])) {
2617  set_hash("zone", s[8]);
2618  set_hash("offset", date_zone_to_diff(s[8]));
2619  }
2620 
2621  return 1;
2622 }
2623 
2624 static int
2625 xmlschema_datetime(VALUE str, VALUE hash)
2626 {
2627  static const char pat_source[] =
2628  "\\A\\s*(-?\\d{4,})(?:-(\\d{2})(?:-(\\d{2}))?)?"
2629  "(?:t"
2630  "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?)?"
2631  "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
2632  static VALUE pat = Qnil;
2633 
2634  REGCOMP_I(pat);
2635  MATCH(str, pat, xmlschema_datetime_cb);
2636 }
2637 
2638 #undef SNUM
2639 #define SNUM 5
2640 
2641 static int
2642 xmlschema_time_cb(VALUE m, VALUE hash)
2643 {
2644  VALUE s[SNUM + 1];
2645 
2646  {
2647  int i;
2648  s[0] = Qnil;
2649  for (i = 1; i <= SNUM; i++)
2650  s[i] = rb_reg_nth_match(i, m);
2651  }
2652 
2653  set_hash("hour", str2num(s[1]));
2654  set_hash("min", str2num(s[2]));
2655  if (!NIL_P(s[3]))
2656  set_hash("sec", str2num(s[3]));
2657  if (!NIL_P(s[4]))
2658  set_hash("sec_fraction", sec_fraction(s[4]));
2659  if (!NIL_P(s[5])) {
2660  set_hash("zone", s[5]);
2661  set_hash("offset", date_zone_to_diff(s[5]));
2662  }
2663 
2664  return 1;
2665 }
2666 
2667 static int
2668 xmlschema_time(VALUE str, VALUE hash)
2669 {
2670  static const char pat_source[] =
2671  "\\A\\s*(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?"
2672  "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
2673  static VALUE pat = Qnil;
2674 
2675  REGCOMP_I(pat);
2676  MATCH(str, pat, xmlschema_time_cb);
2677 }
2678 
2679 #undef SNUM
2680 #define SNUM 4
2681 
2682 static int
2683 xmlschema_trunc_cb(VALUE m, VALUE hash)
2684 {
2685  VALUE s[SNUM + 1];
2686 
2687  {
2688  int i;
2689  s[0] = Qnil;
2690  for (i = 1; i <= SNUM; i++)
2691  s[i] = rb_reg_nth_match(i, m);
2692  }
2693 
2694  if (!NIL_P(s[1]))
2695  set_hash("mon", str2num(s[1]));
2696  if (!NIL_P(s[2]))
2697  set_hash("mday", str2num(s[2]));
2698  if (!NIL_P(s[3]))
2699  set_hash("mday", str2num(s[3]));
2700  if (!NIL_P(s[4])) {
2701  set_hash("zone", s[4]);
2702  set_hash("offset", date_zone_to_diff(s[4]));
2703  }
2704 
2705  return 1;
2706 }
2707 
2708 static int
2709 xmlschema_trunc(VALUE str, VALUE hash)
2710 {
2711  static const char pat_source[] =
2712  "\\A\\s*(?:--(\\d{2})(?:-(\\d{2}))?|---(\\d{2}))"
2713  "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
2714  static VALUE pat = Qnil;
2715 
2716  REGCOMP_I(pat);
2717  MATCH(str, pat, xmlschema_trunc_cb);
2718 }
2719 
2720 VALUE
2722 {
2723  VALUE backref, hash;
2724 
2725  backref = rb_backref_get();
2726  rb_match_busy(backref);
2727 
2728  hash = rb_hash_new();
2729 
2730  if (xmlschema_datetime(str, hash))
2731  goto ok;
2732  if (xmlschema_time(str, hash))
2733  goto ok;
2734  if (xmlschema_trunc(str, hash))
2735  goto ok;
2736 
2737  ok:
2738  rb_backref_set(backref);
2739 
2740  return hash;
2741 }
2742 
2743 #undef SNUM
2744 #define SNUM 8
2745 
2746 static int
2747 rfc2822_cb(VALUE m, VALUE hash)
2748 {
2749  VALUE s[SNUM + 1], y;
2750 
2751  {
2752  int i;
2753  s[0] = Qnil;
2754  for (i = 1; i <= SNUM; i++)
2755  s[i] = rb_reg_nth_match(i, m);
2756  }
2757 
2758  if (!NIL_P(s[1])) {
2759  set_hash("wday", INT2FIX(day_num(s[1])));
2760  }
2761  set_hash("mday", str2num(s[2]));
2762  set_hash("mon", INT2FIX(mon_num(s[3])));
2763  y = str2num(s[4]);
2764  if (RSTRING_LEN(s[4]) < 4)
2765  y = comp_year50(y);
2766  set_hash("year", y);
2767  set_hash("hour", str2num(s[5]));
2768  set_hash("min", str2num(s[6]));
2769  if (!NIL_P(s[7]))
2770  set_hash("sec", str2num(s[7]));
2771  set_hash("zone", s[8]);
2772  set_hash("offset", date_zone_to_diff(s[8]));
2773 
2774  return 1;
2775 }
2776 
2777 static int
2778 rfc2822(VALUE str, VALUE hash)
2779 {
2780  static const char pat_source[] =
2781  "\\A\\s*(?:(" ABBR_DAYS ")\\s*,\\s+)?"
2782  "(\\d{1,2})\\s+"
2783  "(" ABBR_MONTHS ")\\s+"
2784  "(-?\\d{2,})\\s+"
2785  "(\\d{2}):(\\d{2})(?::(\\d{2}))?\\s*"
2786  "([-+]\\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\\s*\\z";
2787  static VALUE pat = Qnil;
2788 
2789  REGCOMP_I(pat);
2790  MATCH(str, pat, rfc2822_cb);
2791 }
2792 
2793 VALUE
2795 {
2796  VALUE backref, hash;
2797 
2798  backref = rb_backref_get();
2799  rb_match_busy(backref);
2800 
2801  hash = rb_hash_new();
2802  rfc2822(str, hash);
2803  rb_backref_set(backref);
2804  return hash;
2805 }
2806 
2807 #undef SNUM
2808 #define SNUM 8
2809 
2810 static int
2811 httpdate_type1_cb(VALUE m, VALUE hash)
2812 {
2813  VALUE s[SNUM + 1];
2814 
2815  {
2816  int i;
2817  s[0] = Qnil;
2818  for (i = 1; i <= SNUM; i++)
2819  s[i] = rb_reg_nth_match(i, m);
2820  }
2821 
2822  set_hash("wday", INT2FIX(day_num(s[1])));
2823  set_hash("mday", str2num(s[2]));
2824  set_hash("mon", INT2FIX(mon_num(s[3])));
2825  set_hash("year", str2num(s[4]));
2826  set_hash("hour", str2num(s[5]));
2827  set_hash("min", str2num(s[6]));
2828  set_hash("sec", str2num(s[7]));
2829  set_hash("zone", s[8]);
2830  set_hash("offset", INT2FIX(0));
2831 
2832  return 1;
2833 }
2834 
2835 static int
2836 httpdate_type1(VALUE str, VALUE hash)
2837 {
2838  static const char pat_source[] =
2839  "\\A\\s*(" ABBR_DAYS ")\\s*,\\s+"
2840  "(\\d{2})\\s+"
2841  "(" ABBR_MONTHS ")\\s+"
2842  "(-?\\d{4})\\s+"
2843  "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
2844  "(gmt)\\s*\\z";
2845  static VALUE pat = Qnil;
2846 
2847  REGCOMP_I(pat);
2848  MATCH(str, pat, httpdate_type1_cb);
2849 }
2850 
2851 #undef SNUM
2852 #define SNUM 8
2853 
2854 static int
2855 httpdate_type2_cb(VALUE m, VALUE hash)
2856 {
2857  VALUE s[SNUM + 1], y;
2858 
2859  {
2860  int i;
2861  s[0] = Qnil;
2862  for (i = 1; i <= SNUM; i++)
2863  s[i] = rb_reg_nth_match(i, m);
2864  }
2865 
2866  set_hash("wday", INT2FIX(day_num(s[1])));
2867  set_hash("mday", str2num(s[2]));
2868  set_hash("mon", INT2FIX(mon_num(s[3])));
2869  y = str2num(s[4]);
2870  if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99)))
2871  y = comp_year69(y);
2872  set_hash("year", y);
2873  set_hash("hour", str2num(s[5]));
2874  set_hash("min", str2num(s[6]));
2875  set_hash("sec", str2num(s[7]));
2876  set_hash("zone", s[8]);
2877  set_hash("offset", INT2FIX(0));
2878 
2879  return 1;
2880 }
2881 
2882 static int
2883 httpdate_type2(VALUE str, VALUE hash)
2884 {
2885  static const char pat_source[] =
2886  "\\A\\s*(" DAYS ")\\s*,\\s+"
2887  "(\\d{2})\\s*-\\s*"
2888  "(" ABBR_MONTHS ")\\s*-\\s*"
2889  "(\\d{2})\\s+"
2890  "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
2891  "(gmt)\\s*\\z";
2892  static VALUE pat = Qnil;
2893 
2894  REGCOMP_I(pat);
2895  MATCH(str, pat, httpdate_type2_cb);
2896 }
2897 
2898 #undef SNUM
2899 #define SNUM 7
2900 
2901 static int
2902 httpdate_type3_cb(VALUE m, VALUE hash)
2903 {
2904  VALUE s[SNUM + 1];
2905 
2906  {
2907  int i;
2908  s[0] = Qnil;
2909  for (i = 1; i <= SNUM; i++)
2910  s[i] = rb_reg_nth_match(i, m);
2911  }
2912 
2913  set_hash("wday", INT2FIX(day_num(s[1])));
2914  set_hash("mon", INT2FIX(mon_num(s[2])));
2915  set_hash("mday", str2num(s[3]));
2916  set_hash("hour", str2num(s[4]));
2917  set_hash("min", str2num(s[5]));
2918  set_hash("sec", str2num(s[6]));
2919  set_hash("year", str2num(s[7]));
2920 
2921  return 1;
2922 }
2923 
2924 static int
2925 httpdate_type3(VALUE str, VALUE hash)
2926 {
2927  static const char pat_source[] =
2928  "\\A\\s*(" ABBR_DAYS ")\\s+"
2929  "(" ABBR_MONTHS ")\\s+"
2930  "(\\d{1,2})\\s+"
2931  "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
2932  "(\\d{4})\\s*\\z";
2933  static VALUE pat = Qnil;
2934 
2935  REGCOMP_I(pat);
2936  MATCH(str, pat, httpdate_type3_cb);
2937 }
2938 
2939 VALUE
2941 {
2942  VALUE backref, hash;
2943 
2944  backref = rb_backref_get();
2945  rb_match_busy(backref);
2946 
2947  hash = rb_hash_new();
2948 
2949  if (httpdate_type1(str, hash))
2950  goto ok;
2951  if (httpdate_type2(str, hash))
2952  goto ok;
2953  if (httpdate_type3(str, hash))
2954  goto ok;
2955 
2956  ok:
2957  rb_backref_set(backref);
2958 
2959  return hash;
2960 }
2961 
2962 #undef SNUM
2963 #define SNUM 9
2964 
2965 static int
2966 jisx0301_cb(VALUE m, VALUE hash)
2967 {
2968  VALUE s[SNUM + 1];
2969  int ep;
2970 
2971  {
2972  int i;
2973  s[0] = Qnil;
2974  for (i = 1; i <= SNUM; i++)
2975  s[i] = rb_reg_nth_match(i, m);
2976  }
2977 
2978  ep = gengo(NIL_P(s[1]) ? JISX0301_DEFAULT_ERA : *RSTRING_PTR(s[1]));
2979  set_hash("year", f_add(str2num(s[2]), INT2FIX(ep)));
2980  set_hash("mon", str2num(s[3]));
2981  set_hash("mday", str2num(s[4]));
2982  if (!NIL_P(s[5])) {
2983  set_hash("hour", str2num(s[5]));
2984  if (!NIL_P(s[6]))
2985  set_hash("min", str2num(s[6]));
2986  if (!NIL_P(s[7]))
2987  set_hash("sec", str2num(s[7]));
2988  }
2989  if (!NIL_P(s[8]))
2990  set_hash("sec_fraction", sec_fraction(s[8]));
2991  if (!NIL_P(s[9])) {
2992  set_hash("zone", s[9]);
2993  set_hash("offset", date_zone_to_diff(s[9]));
2994  }
2995 
2996  return 1;
2997 }
2998 
2999 static int
3000 jisx0301(VALUE str, VALUE hash)
3001 {
3002  static const char pat_source[] =
3003  "\\A\\s*([" JISX0301_ERA_INITIALS "])?(\\d{2})\\.(\\d{2})\\.(\\d{2})"
3004  "(?:t"
3005  "(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d*))?)?"
3006  "(z|[-+]\\d{2}(?::?\\d{2})?)?)?)?\\s*\\z";
3007  static VALUE pat = Qnil;
3008 
3009  REGCOMP_I(pat);
3010  MATCH(str, pat, jisx0301_cb);
3011 }
3012 
3013 VALUE
3015 {
3016  VALUE backref, hash;
3017 
3018  backref = rb_backref_get();
3019  rb_match_busy(backref);
3020 
3021  hash = rb_hash_new();
3022  if (jisx0301(str, hash))
3023  goto ok;
3024  hash = date__iso8601(str);
3025 
3026  ok:
3027  rb_backref_set(backref);
3028  return hash;
3029 }
3030 
3031 /*
3032 Local variables:
3033 c-file-style: "ruby"
3034 End:
3035 */
zonetab
const struct zone * zonetab(register const char *str, register size_t len)
Definition: zonetab.h:806
rb_match_busy
void rb_match_busy(VALUE)
Definition: re.c:1287
HAVE_DOT
#define HAVE_DOT
REGCOMP_0
#define REGCOMP_0(pat)
Definition: date_parse.c:289
id
const int id
Definition: nkf.c:209
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:1523
rb_gc_register_mark_object
void rb_gc_register_mark_object(VALUE obj)
Definition: gc.c:7066
s2
const char * s2
Definition: rb_mjit_min_header-2.7.2.h:5489
FPT
#define FPT
Definition: vsnprintf.c:537
date_zone_to_diff
VALUE date_zone_to_diff(VALUE str)
Definition: date_parse.c:410
date__jisx0301
VALUE date__jisx0301(VALUE)
int
__inline__ int
Definition: rb_mjit_min_header-2.7.2.h:2877
HAVE_DASH
#define HAVE_DASH
asp_string
#define asp_string()
Definition: date_parse.c:61
MAX_WORD_LENGTH
#define MAX_WORD_LENGTH
Definition: zonetab.h:45
ABBR_DAYS
#define ABBR_DAYS
Definition: date_parse.c:253
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:263
bp
#define bp()
Definition: internal.h:1445
JISX0301_DEFAULT_ERA
#define JISX0301_DEFAULT_ERA
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
re.h
i
uint32_t i
Definition: rb_mjit_min_header-2.7.2.h:5499
NUM2LONG
#define NUM2LONG(x)
Definition: ruby.h:679
rb_int_positive_pow
RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y)
Definition: numeric.c:4033
VALUE
unsigned long VALUE
Definition: ruby.h:102
encoding.h
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:560
date__rfc3339
VALUE date__rfc3339(VALUE)
f_to_s
#define f_to_s(x)
Definition: date_parse.c:31
HAVE_ELEM_P
#define HAVE_ELEM_P(x)
iso8601_bas_time_cb
#define iso8601_bas_time_cb
zone
Definition: zonetab.h:35
rb_str_dup
VALUE rb_str_dup(VALUE)
Definition: string.c:1516
SNUM
#define SNUM
Qfalse
#define Qfalse
Definition: ruby.h:467
HAVE_DIGIT
#define HAVE_DIGIT
MATCH
#define MATCH(s, p, c)
Definition: date_parse.c:292
sizeof_array
#define sizeof_array(o)
Definition: date_parse.c:15
rb_reg_new
VALUE rb_reg_new(const char *, long, int)
Definition: re.c:2947
strlen
size_t strlen(const char *)
set_hash
#define set_hash(k, v)
Definition: date_parse.c:43
ref_hash
#define ref_hash(k)
Definition: date_parse.c:44
LONG2NUM
#define LONG2NUM(x)
Definition: ruby.h:1644
f_ge_p
#define f_ge_p(x, y)
Definition: date_parse.c:29
rb_rational_new2
#define rb_rational_new2(x, y)
Definition: intern.h:180
issign
#define issign(c)
Definition: date_parse.c:60
SUBS
#define SUBS(s, p, c)
Definition: date_parse.c:334
f_aset2
#define f_aset2(o, i, j, v)
Definition: date_parse.c:39
ALLOCV_END
#define ALLOCV_END(v)
Definition: ruby.h:1750
REGCOMP_I
#define REGCOMP_I(pat)
Definition: date_parse.c:290
h
size_t st_index_t h
Definition: rb_mjit_min_header-2.7.2.h:5497
ALLOCV_N
#define ALLOCV_N(type, v, n)
Definition: ruby.h:1749
ABBR_MONTHS
#define ABBR_MONTHS
Definition: date_parse.c:254
memchr
void * memchr(const void *, int, size_t)
ruby.h
f_begin
#define f_begin(o, i)
Definition: date_parse.c:36
f_negate
#define f_negate(x)
Definition: date_parse.c:17
date__parse
VALUE date__parse(VALUE str, VALUE comp)
rb_backref_get
VALUE rb_backref_get(void)
Definition: vm.c:1304
STRTOUL
#define STRTOUL(str, endptr, base)
Definition: ruby.h:2327
strncasecmp
int strncasecmp(const char *, const char *, size_t) __attribute__((__pure__))
ruby_scan_digits
RUBY_EXTERN unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow)
Definition: util.c:97
rb_backref_set
void rb_backref_set(VALUE)
Definition: vm.c:1310
zone::offset
int offset
Definition: zonetab.h:37
rb_rational_new
VALUE rb_rational_new(VALUE, VALUE)
Definition: rational.c:1945
date__rfc2822
VALUE date__rfc2822(VALUE)
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4322
str2num
#define str2num(s)
Definition: date_parse.c:48
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2965
f_match
#define f_match(r, s)
Definition: date_parse.c:33
f
#define f
DAYS
#define DAYS
Definition: date_parse.c:251
rb_str_subseq
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:2474
f_add
#define f_add(x, y)
Definition: date_parse.c:18
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
date__httpdate
VALUE date__httpdate(VALUE)
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
ssize_t
_ssize_t ssize_t
Definition: rb_mjit_min_header-2.7.2.h:1332
NIL_P
#define NIL_P(v)
Definition: ruby.h:482
zonetab.h
HAVE_ALPHA
#define HAVE_ALPHA
RUBY_EXTERN
#define RUBY_EXTERN
Definition: missing.h:77
JISX0301_ERA_INITIALS
#define JISX0301_ERA_INITIALS
rb_reg_nth_match
VALUE rb_reg_nth_match(int, VALUE)
Definition: re.c:1706
Qtrue
#define Qtrue
Definition: ruby.h:468
v
int VALUE v
Definition: rb_mjit_min_header-2.7.2.h:12380
len
uint8_t len
Definition: escape.c:17
date__iso8601
VALUE date__iso8601(VALUE)
HAVE_SLASH
#define HAVE_SLASH
T_STRING
#define T_STRING
Definition: ruby.h:528
date__xmlschema
VALUE date__xmlschema(VALUE)
f_gsub_bang
#define f_gsub_bang(s, r, x)
Definition: date_parse.c:41
del_hash
#define del_hash(k)
Definition: date_parse.c:45
rb_str_new_cstr
#define rb_str_new_cstr(str)
Definition: rb_mjit_min_header-2.7.2.h:6152
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:715
Qnil
#define Qnil
Definition: ruby.h:469
rb_str_new
#define rb_str_new(str, len)
Definition: rb_mjit_min_header-2.7.2.h:6151
f_end
#define f_end(o, i)
Definition: date_parse.c:37
RB_GC_GUARD
#define RB_GC_GUARD(v)
Definition: ruby.h:585
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:1005
f_le_p
#define f_le_p(x, y)
Definition: date_parse.c:28
RTEST
#define RTEST(v)
Definition: ruby.h:481
f_expt
#define f_expt(x, y)
Definition: date_parse.c:24
strcmp
int strcmp(const char *, const char *)
cstr2num
#define cstr2num(s)
Definition: date_parse.c:47
RSTRING_END
#define RSTRING_END(str)
Definition: ruby.h:1013
n
const char size_t n
Definition: rb_mjit_min_header-2.7.2.h:5491