date 0.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of date might be problematic. Click here for more details.

@@ -0,0 +1,703 @@
1
+ /*
2
+ date_strptime.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
+ static const char *day_names[] = {
11
+ "Sunday", "Monday", "Tuesday", "Wednesday",
12
+ "Thursday", "Friday", "Saturday",
13
+ "Sun", "Mon", "Tue", "Wed",
14
+ "Thu", "Fri", "Sat"
15
+ };
16
+
17
+ static const char *month_names[] = {
18
+ "January", "February", "March", "April",
19
+ "May", "June", "July", "August", "September",
20
+ "October", "November", "December",
21
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
22
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
23
+ };
24
+
25
+ static const char *merid_names[] = {
26
+ "am", "pm",
27
+ "a.m.", "p.m."
28
+ };
29
+
30
+ static const char *extz_pats[] = {
31
+ ":z",
32
+ "::z",
33
+ ":::z"
34
+ };
35
+
36
+ #define sizeof_array(o) (sizeof o / sizeof o[0])
37
+
38
+ #define f_negate(x) rb_funcall(x, rb_intern("-@"), 0)
39
+ #define f_add(x,y) rb_funcall(x, '+', 1, y)
40
+ #define f_sub(x,y) rb_funcall(x, '-', 1, y)
41
+ #define f_mul(x,y) rb_funcall(x, '*', 1, y)
42
+ #define f_div(x,y) rb_funcall(x, '/', 1, y)
43
+ #define f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y)
44
+ #define f_mod(x,y) rb_funcall(x, '%', 1, y)
45
+ #define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y)
46
+
47
+ #define f_lt_p(x,y) rb_funcall(x, '<', 1, y)
48
+ #define f_gt_p(x,y) rb_funcall(x, '>', 1, y)
49
+ #define f_le_p(x,y) rb_funcall(x, rb_intern("<="), 1, y)
50
+ #define f_ge_p(x,y) rb_funcall(x, rb_intern(">="), 1, y)
51
+
52
+ #define f_match(r,s) rb_funcall(r, rb_intern("match"), 1, s)
53
+ #define f_aref(o,i) rb_funcall(o, rb_intern("[]"), 1, i)
54
+ #define f_end(o,i) rb_funcall(o, rb_intern("end"), 1, i)
55
+
56
+ #define issign(c) ((c) == '-' || (c) == '+')
57
+
58
+ static int
59
+ num_pattern_p(const char *s)
60
+ {
61
+ if (isdigit((unsigned char)*s))
62
+ return 1;
63
+ if (*s == '%') {
64
+ s++;
65
+ if (*s == 'E' || *s == 'O')
66
+ s++;
67
+ if (*s &&
68
+ (strchr("CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy", *s) ||
69
+ isdigit((unsigned char)*s)))
70
+ return 1;
71
+ }
72
+ return 0;
73
+ }
74
+
75
+ #define NUM_PATTERN_P() num_pattern_p(&fmt[fi + 1])
76
+
77
+ static long
78
+ read_digits(const char *s, VALUE *n, size_t width)
79
+ {
80
+ size_t l;
81
+
82
+ l = strspn(s, "0123456789");
83
+
84
+ if (l == 0)
85
+ return 0;
86
+
87
+ if (width < l)
88
+ l = width;
89
+
90
+ if ((4 * l * sizeof(char)) <= (sizeof(long)*CHAR_BIT)) {
91
+ const char *os = s;
92
+ long v;
93
+
94
+ v = 0;
95
+ while ((size_t)(s - os) < l) {
96
+ v *= 10;
97
+ v += *s - '0';
98
+ s++;
99
+ }
100
+ if (os == s)
101
+ return 0;
102
+ *n = LONG2NUM(v);
103
+ return l;
104
+ }
105
+ else {
106
+ VALUE vbuf = 0;
107
+ char *s2 = ALLOCV_N(char, vbuf, l + 1);
108
+ memcpy(s2, s, l);
109
+ s2[l] = '\0';
110
+ *n = rb_cstr_to_inum(s2, 10, 0);
111
+ ALLOCV_END(vbuf);
112
+ return l;
113
+ }
114
+ }
115
+
116
+ #define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v)
117
+ #define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k)))
118
+ #define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k)))
119
+
120
+ #define fail() \
121
+ { \
122
+ set_hash("_fail", Qtrue); \
123
+ return 0; \
124
+ }
125
+
126
+ #define fail_p() (!NIL_P(ref_hash("_fail")))
127
+
128
+ #define READ_DIGITS(n,w) \
129
+ { \
130
+ size_t l; \
131
+ l = read_digits(&str[si], &n, w); \
132
+ if (l == 0) \
133
+ fail(); \
134
+ si += l; \
135
+ }
136
+
137
+ #define READ_DIGITS_MAX(n) READ_DIGITS(n, LONG_MAX)
138
+
139
+ static int
140
+ valid_range_p(VALUE v, int a, int b)
141
+ {
142
+ if (FIXNUM_P(v)) {
143
+ int vi = FIX2INT(v);
144
+ return !(vi < a || vi > b);
145
+ }
146
+ return !(f_lt_p(v, INT2NUM(a)) || f_gt_p(v, INT2NUM(b)));
147
+ }
148
+
149
+ #define recur(fmt) \
150
+ { \
151
+ size_t l; \
152
+ l = date__strptime_internal(&str[si], slen - si, \
153
+ fmt, sizeof fmt - 1, hash); \
154
+ if (fail_p()) \
155
+ return 0; \
156
+ si += l; \
157
+ }
158
+
159
+ VALUE date_zone_to_diff(VALUE);
160
+
161
+ static size_t
162
+ date__strptime_internal(const char *str, size_t slen,
163
+ const char *fmt, size_t flen, VALUE hash)
164
+ {
165
+ size_t si, fi;
166
+ int c;
167
+
168
+ si = fi = 0;
169
+
170
+ while (fi < flen) {
171
+
172
+ switch (fmt[fi]) {
173
+ case '%':
174
+
175
+ again:
176
+ fi++;
177
+ c = fmt[fi];
178
+
179
+ switch (c) {
180
+ case 'E':
181
+ if (fmt[fi + 1] && strchr("cCxXyY", fmt[fi + 1]))
182
+ goto again;
183
+ fi--;
184
+ goto ordinal;
185
+ case 'O':
186
+ if (fmt[fi + 1] && strchr("deHImMSuUVwWy", fmt[fi + 1]))
187
+ goto again;
188
+ fi--;
189
+ goto ordinal;
190
+ case ':':
191
+ {
192
+ int i;
193
+
194
+ for (i = 0; i < (int)sizeof_array(extz_pats); i++)
195
+ if (strncmp(extz_pats[i], &fmt[fi],
196
+ strlen(extz_pats[i])) == 0) {
197
+ fi += i;
198
+ goto again;
199
+ }
200
+ fail();
201
+ }
202
+
203
+ case 'A':
204
+ case 'a':
205
+ {
206
+ int i;
207
+
208
+ for (i = 0; i < (int)sizeof_array(day_names); i++) {
209
+ size_t l = strlen(day_names[i]);
210
+ if (strncasecmp(day_names[i], &str[si], l) == 0) {
211
+ si += l;
212
+ set_hash("wday", INT2FIX(i % 7));
213
+ goto matched;
214
+ }
215
+ }
216
+ fail();
217
+ }
218
+ case 'B':
219
+ case 'b':
220
+ case 'h':
221
+ {
222
+ int i;
223
+
224
+ for (i = 0; i < (int)sizeof_array(month_names); i++) {
225
+ size_t l = strlen(month_names[i]);
226
+ if (strncasecmp(month_names[i], &str[si], l) == 0) {
227
+ si += l;
228
+ set_hash("mon", INT2FIX((i % 12) + 1));
229
+ goto matched;
230
+ }
231
+ }
232
+ fail();
233
+ }
234
+
235
+ case 'C':
236
+ {
237
+ VALUE n;
238
+
239
+ if (NUM_PATTERN_P())
240
+ READ_DIGITS(n, 2)
241
+ else
242
+ READ_DIGITS_MAX(n)
243
+ set_hash("_cent", n);
244
+ goto matched;
245
+ }
246
+
247
+ case 'c':
248
+ recur("%a %b %e %H:%M:%S %Y");
249
+ goto matched;
250
+
251
+ case 'D':
252
+ recur("%m/%d/%y");
253
+ goto matched;
254
+
255
+ case 'd':
256
+ case 'e':
257
+ {
258
+ VALUE n;
259
+
260
+ if (str[si] == ' ') {
261
+ si++;
262
+ READ_DIGITS(n, 1);
263
+ } else {
264
+ READ_DIGITS(n, 2);
265
+ }
266
+ if (!valid_range_p(n, 1, 31))
267
+ fail();
268
+ set_hash("mday", n);
269
+ goto matched;
270
+ }
271
+
272
+ case 'F':
273
+ recur("%Y-%m-%d");
274
+ goto matched;
275
+
276
+ case 'G':
277
+ {
278
+ VALUE n;
279
+
280
+ if (NUM_PATTERN_P())
281
+ READ_DIGITS(n, 4)
282
+ else
283
+ READ_DIGITS_MAX(n)
284
+ set_hash("cwyear", n);
285
+ goto matched;
286
+ }
287
+
288
+ case 'g':
289
+ {
290
+ VALUE n;
291
+
292
+ READ_DIGITS(n, 2);
293
+ if (!valid_range_p(n, 0, 99))
294
+ fail();
295
+ set_hash("cwyear",n);
296
+ if (NIL_P(ref_hash("_cent")))
297
+ set_hash("_cent",
298
+ INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20));
299
+ goto matched;
300
+ }
301
+
302
+ case 'H':
303
+ case 'k':
304
+ {
305
+ VALUE n;
306
+
307
+ if (str[si] == ' ') {
308
+ si++;
309
+ READ_DIGITS(n, 1);
310
+ } else {
311
+ READ_DIGITS(n, 2);
312
+ }
313
+ if (!valid_range_p(n, 0, 24))
314
+ fail();
315
+ set_hash("hour", n);
316
+ goto matched;
317
+ }
318
+
319
+ case 'I':
320
+ case 'l':
321
+ {
322
+ VALUE n;
323
+
324
+ if (str[si] == ' ') {
325
+ si++;
326
+ READ_DIGITS(n, 1);
327
+ } else {
328
+ READ_DIGITS(n, 2);
329
+ }
330
+ if (!valid_range_p(n, 1, 12))
331
+ fail();
332
+ set_hash("hour", n);
333
+ goto matched;
334
+ }
335
+
336
+ case 'j':
337
+ {
338
+ VALUE n;
339
+
340
+ READ_DIGITS(n, 3);
341
+ if (!valid_range_p(n, 1, 366))
342
+ fail();
343
+ set_hash("yday", n);
344
+ goto matched;
345
+ }
346
+
347
+ case 'L':
348
+ case 'N':
349
+ {
350
+ VALUE n;
351
+ int sign = 1;
352
+ size_t osi;
353
+
354
+ if (issign(str[si])) {
355
+ if (str[si] == '-')
356
+ sign = -1;
357
+ si++;
358
+ }
359
+ osi = si;
360
+ if (NUM_PATTERN_P())
361
+ READ_DIGITS(n, c == 'L' ? 3 : 9)
362
+ else
363
+ READ_DIGITS_MAX(n)
364
+ if (sign == -1)
365
+ n = f_negate(n);
366
+ set_hash("sec_fraction",
367
+ rb_rational_new2(n,
368
+ f_expt(INT2FIX(10),
369
+ ULONG2NUM(si - osi))));
370
+ goto matched;
371
+ }
372
+
373
+ case 'M':
374
+ {
375
+ VALUE n;
376
+
377
+ READ_DIGITS(n, 2);
378
+ if (!valid_range_p(n, 0, 59))
379
+ fail();
380
+ set_hash("min", n);
381
+ goto matched;
382
+ }
383
+
384
+ case 'm':
385
+ {
386
+ VALUE n;
387
+
388
+ READ_DIGITS(n, 2);
389
+ if (!valid_range_p(n, 1, 12))
390
+ fail();
391
+ set_hash("mon", n);
392
+ goto matched;
393
+ }
394
+
395
+ case 'n':
396
+ case 't':
397
+ recur(" ");
398
+ goto matched;
399
+
400
+ case 'P':
401
+ case 'p':
402
+ {
403
+ int i;
404
+
405
+ for (i = 0; i < 4; i++) {
406
+ size_t l = strlen(merid_names[i]);
407
+ if (strncasecmp(merid_names[i], &str[si], l) == 0) {
408
+ si += l;
409
+ set_hash("_merid", INT2FIX((i % 2) == 0 ? 0 : 12));
410
+ goto matched;
411
+ }
412
+ }
413
+ fail();
414
+ }
415
+
416
+ case 'Q':
417
+ {
418
+ VALUE n;
419
+ int sign = 1;
420
+
421
+ if (str[si] == '-') {
422
+ sign = -1;
423
+ si++;
424
+ }
425
+ READ_DIGITS_MAX(n);
426
+ if (sign == -1)
427
+ n = f_negate(n);
428
+ set_hash("seconds",
429
+ rb_rational_new2(n,
430
+ f_expt(INT2FIX(10),
431
+ INT2FIX(3))));
432
+ goto matched;
433
+ }
434
+
435
+ case 'R':
436
+ recur("%H:%M");
437
+ goto matched;
438
+
439
+ case 'r':
440
+ recur("%I:%M:%S %p");
441
+ goto matched;
442
+
443
+ case 'S':
444
+ {
445
+ VALUE n;
446
+
447
+ READ_DIGITS(n, 2);
448
+ if (!valid_range_p(n, 0, 60))
449
+ fail();
450
+ set_hash("sec", n);
451
+ goto matched;
452
+ }
453
+
454
+ case 's':
455
+ {
456
+ VALUE n;
457
+ int sign = 1;
458
+
459
+ if (str[si] == '-') {
460
+ sign = -1;
461
+ si++;
462
+ }
463
+ READ_DIGITS_MAX(n);
464
+ if (sign == -1)
465
+ n = f_negate(n);
466
+ set_hash("seconds", n);
467
+ goto matched;
468
+ }
469
+
470
+ case 'T':
471
+ recur("%H:%M:%S");
472
+ goto matched;
473
+
474
+ case 'U':
475
+ case 'W':
476
+ {
477
+ VALUE n;
478
+
479
+ READ_DIGITS(n, 2);
480
+ if (!valid_range_p(n, 0, 53))
481
+ fail();
482
+ set_hash(c == 'U' ? "wnum0" : "wnum1", n);
483
+ goto matched;
484
+ }
485
+
486
+ case 'u':
487
+ {
488
+ VALUE n;
489
+
490
+ READ_DIGITS(n, 1);
491
+ if (!valid_range_p(n, 1, 7))
492
+ fail();
493
+ set_hash("cwday", n);
494
+ goto matched;
495
+ }
496
+
497
+ case 'V':
498
+ {
499
+ VALUE n;
500
+
501
+ READ_DIGITS(n, 2);
502
+ if (!valid_range_p(n, 1, 53))
503
+ fail();
504
+ set_hash("cweek", n);
505
+ goto matched;
506
+ }
507
+
508
+ case 'v':
509
+ recur("%e-%b-%Y");
510
+ goto matched;
511
+
512
+ case 'w':
513
+ {
514
+ VALUE n;
515
+
516
+ READ_DIGITS(n, 1);
517
+ if (!valid_range_p(n, 0, 6))
518
+ fail();
519
+ set_hash("wday", n);
520
+ goto matched;
521
+ }
522
+
523
+ case 'X':
524
+ recur("%H:%M:%S");
525
+ goto matched;
526
+
527
+ case 'x':
528
+ recur("%m/%d/%y");
529
+ goto matched;
530
+
531
+ case 'Y':
532
+ {
533
+ VALUE n;
534
+ int sign = 1;
535
+
536
+ if (issign(str[si])) {
537
+ if (str[si] == '-')
538
+ sign = -1;
539
+ si++;
540
+ }
541
+ if (NUM_PATTERN_P())
542
+ READ_DIGITS(n, 4)
543
+ else
544
+ READ_DIGITS_MAX(n)
545
+ if (sign == -1)
546
+ n = f_negate(n);
547
+ set_hash("year", n);
548
+ goto matched;
549
+ }
550
+
551
+ case 'y':
552
+ {
553
+ VALUE n;
554
+ int sign = 1;
555
+
556
+ READ_DIGITS(n, 2);
557
+ if (!valid_range_p(n, 0, 99))
558
+ fail();
559
+ if (sign == -1)
560
+ n = f_negate(n);
561
+ set_hash("year", n);
562
+ if (NIL_P(ref_hash("_cent")))
563
+ set_hash("_cent",
564
+ INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20));
565
+ goto matched;
566
+ }
567
+
568
+ case 'Z':
569
+ case 'z':
570
+ {
571
+ static const char pat_source[] =
572
+ "\\A("
573
+ "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?"
574
+ "|(?-i:[[:alpha:].\\s]+)(?:standard|daylight)\\s+time\\b"
575
+ "|(?-i:[[:alpha:]]+)(?:\\s+dst)?\\b"
576
+ ")";
577
+ static VALUE pat = Qnil;
578
+ VALUE m, b;
579
+
580
+ if (NIL_P(pat)) {
581
+ pat = rb_reg_new(pat_source, sizeof pat_source - 1,
582
+ ONIG_OPTION_IGNORECASE);
583
+ rb_gc_register_mark_object(pat);
584
+ }
585
+
586
+ b = rb_backref_get();
587
+ rb_match_busy(b);
588
+ m = f_match(pat, rb_usascii_str_new2(&str[si]));
589
+
590
+ if (!NIL_P(m)) {
591
+ VALUE s, l, o;
592
+
593
+ s = rb_reg_nth_match(1, m);
594
+ l = f_end(m, INT2FIX(0));
595
+ o = date_zone_to_diff(s);
596
+ si += NUM2LONG(l);
597
+ set_hash("zone", s);
598
+ set_hash("offset", o);
599
+ rb_backref_set(b);
600
+ goto matched;
601
+ }
602
+ rb_backref_set(b);
603
+ fail();
604
+ }
605
+
606
+ case '%':
607
+ if (str[si] != '%')
608
+ fail();
609
+ si++;
610
+ goto matched;
611
+
612
+ case '+':
613
+ recur("%a %b %e %H:%M:%S %Z %Y");
614
+ goto matched;
615
+
616
+ default:
617
+ if (str[si] != '%')
618
+ fail();
619
+ si++;
620
+ if (fi < flen)
621
+ if (str[si] != fmt[fi])
622
+ fail();
623
+ si++;
624
+ goto matched;
625
+ }
626
+ case ' ':
627
+ case '\t':
628
+ case '\n':
629
+ case '\v':
630
+ case '\f':
631
+ case '\r':
632
+ while (isspace((unsigned char)str[si]))
633
+ si++;
634
+ fi++;
635
+ break;
636
+ default:
637
+ ordinal:
638
+ if (str[si] != fmt[fi])
639
+ fail();
640
+ si++;
641
+ fi++;
642
+ break;
643
+ matched:
644
+ fi++;
645
+ break;
646
+ }
647
+ }
648
+
649
+ return si;
650
+ }
651
+
652
+ VALUE
653
+ date__strptime(const char *str, size_t slen,
654
+ const char *fmt, size_t flen, VALUE hash)
655
+ {
656
+ size_t si;
657
+ VALUE cent, merid;
658
+
659
+ si = date__strptime_internal(str, slen, fmt, flen, hash);
660
+
661
+ if (slen > si) {
662
+ VALUE s;
663
+
664
+ s = rb_usascii_str_new(&str[si], slen - si);
665
+ set_hash("leftover", s);
666
+ }
667
+
668
+ if (fail_p())
669
+ return Qnil;
670
+
671
+ cent = ref_hash("_cent");
672
+ if (!NIL_P(cent)) {
673
+ VALUE year;
674
+
675
+ year = ref_hash("cwyear");
676
+ if (!NIL_P(year))
677
+ set_hash("cwyear", f_add(year, f_mul(cent, INT2FIX(100))));
678
+ year = ref_hash("year");
679
+ if (!NIL_P(year))
680
+ set_hash("year", f_add(year, f_mul(cent, INT2FIX(100))));
681
+ del_hash("_cent");
682
+ }
683
+
684
+ merid = ref_hash("_merid");
685
+ if (!NIL_P(merid)) {
686
+ VALUE hour;
687
+
688
+ hour = ref_hash("hour");
689
+ if (!NIL_P(hour)) {
690
+ hour = f_mod(hour, INT2FIX(12));
691
+ set_hash("hour", f_add(hour, merid));
692
+ }
693
+ del_hash("_merid");
694
+ }
695
+
696
+ return hash;
697
+ }
698
+
699
+ /*
700
+ Local variables:
701
+ c-file-style: "ruby"
702
+ End:
703
+ */