strptime 0.1.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,764 @@
1
+ #include "strptime.h"
2
+ #include <time.h>
3
+
4
+ VALUE rb_cStrptime;
5
+
6
+ #define GetStrptimeval(obj, tobj) ((tobj) = get_strptimeval(obj))
7
+ #define GetNewStrptimeval(obj, tobj) ((tobj) = get_new_strptimeval(obj))
8
+ #define STRPTIME_INIT_P(tobj) ((tobj)->isns)
9
+
10
+ #define LIKELY(x) (__builtin_expect((x), 1))
11
+ #define UNLIKELY(x) (__builtin_expect((x), 0))
12
+
13
+ #define REG_PC (pc)
14
+ #define GET_PC() REG_PC
15
+ #define SET_PC(x) (REG_PC = (x))
16
+ #define GET_CURRENT_INSN() (*GET_PC())
17
+ #define GET_OPERAND(n) (GET_PC()[(n)])
18
+ #define ADD_PC(n) (SET_PC(REG_PC + (n)))
19
+
20
+ #define JUMP(dst) (REG_PC += (dst))
21
+
22
+ #define LABEL(x) INSN_LABEL_##x
23
+ #define ELABEL(x) INSN_ELABEL_##x
24
+ #define LABEL_PTR(x) &&LABEL(x)
25
+
26
+ #define INSN_ENTRY(insn) LABEL(insn) :
27
+
28
+ #define TC_DISPATCH(insn) \
29
+ goto *(void const *)GET_CURRENT_INSN(); \
30
+ ;
31
+ #define END_INSN(insn) TC_DISPATCH(insn);
32
+
33
+ #define INSN_DISPATCH() \
34
+ TC_DISPATCH(__START__) \
35
+ {
36
+
37
+ #define END_INSNS_DISPATCH() \
38
+ rb_bug("unknown insn: %p", GET_CURRENT_INSN()); \
39
+ } /* end of while loop */
40
+
41
+ #define NEXT_INSN() TC_DISPATCH(__NEXT_INSN__)
42
+
43
+ static const char *month_names[] = {
44
+ "January", "February", "March", "April", "May", "June",
45
+ "July", "August", "September", "October", "November", "December",
46
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
47
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
48
+
49
+ #define sizeof_array(o) (sizeof o / sizeof o[0])
50
+
51
+ #define issign(c) ((c) == '-' || (c) == '+')
52
+ #undef isdigit
53
+ #define isdigit(c) ((unsigned char)((c) - '0') <= 9u)
54
+ #undef isspace
55
+ #define isspace(c) \
56
+ ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\v' || (c) == '\f' || \
57
+ (c) == '\r')
58
+
59
+ /* imply NUL-terminated string */
60
+ static size_t
61
+ read_digits(const char *s, int *n, size_t width)
62
+ {
63
+ const char *s0 = s;
64
+ const char *se = s + width;
65
+ int r = 0;
66
+
67
+ for (; s < se && isdigit(*s); s++) {
68
+ r *= 10;
69
+ r += (unsigned char)((*s) - '0');
70
+ }
71
+ *n = r;
72
+ return (size_t)(s - s0);
73
+ }
74
+
75
+ #define fail() \
76
+ { \
77
+ return -1; \
78
+ }
79
+
80
+ #define READ_DIGITS(n, w) \
81
+ { \
82
+ size_t l; \
83
+ l = read_digits(&str[si], &n, w); \
84
+ if (l == 0) fail(); \
85
+ si += l; \
86
+ }
87
+
88
+ static int
89
+ valid_range_p(int v, int a, int b)
90
+ {
91
+ return !(v < a || v > b);
92
+ }
93
+
94
+ static int
95
+ strptime_exec0(void **pc, const char *fmt, const char *str, size_t slen,
96
+ struct timespec *tsp, int *gmtoffp)
97
+ {
98
+ size_t si = 0;
99
+ int year = INT_MAX, mon = -1, mday = -1, hour = -1, min = -1, sec = -1,
100
+ nsec = 0, gmtoff = INT_MAX;
101
+ if (UNLIKELY(tsp == NULL)) {
102
+ static const void *const insns_address_table[] = {
103
+ LABEL_PTR(A), LABEL_PTR(B), LABEL_PTR(C), LABEL_PTR(D),
104
+ LABEL_PTR(E), LABEL_PTR(F), LABEL_PTR(G), LABEL_PTR(H),
105
+ LABEL_PTR(I), NULL, NULL, LABEL_PTR(L),
106
+ LABEL_PTR(M), LABEL_PTR(N), LABEL_PTR(O), LABEL_PTR(P),
107
+ LABEL_PTR(Q), LABEL_PTR(R), LABEL_PTR(S), LABEL_PTR(T),
108
+ LABEL_PTR(U), LABEL_PTR(V), LABEL_PTR(W), LABEL_PTR(X),
109
+ LABEL_PTR(Y), LABEL_PTR(Z), LABEL_PTR(_25), LABEL_PTR(_2b),
110
+ LABEL_PTR(_3a), NULL, LABEL_PTR(_5f), LABEL_PTR(_60),
111
+ LABEL_PTR(a), LABEL_PTR(B), LABEL_PTR(c), LABEL_PTR(d),
112
+ LABEL_PTR(d), NULL, LABEL_PTR(g), LABEL_PTR(B),
113
+ NULL, LABEL_PTR(j), NULL, LABEL_PTR(l),
114
+ LABEL_PTR(m), LABEL_PTR(n), NULL, LABEL_PTR(p),
115
+ NULL, LABEL_PTR(r), LABEL_PTR(s), LABEL_PTR(t),
116
+ LABEL_PTR(u), LABEL_PTR(v), LABEL_PTR(w), LABEL_PTR(x),
117
+ LABEL_PTR(y), LABEL_PTR(z),
118
+ };
119
+ *pc = (void *)insns_address_table;
120
+ return 0;
121
+ }
122
+
123
+ first:
124
+ INSN_DISPATCH();
125
+ INSN_ENTRY(A)
126
+ {
127
+ ADD_PC(1);
128
+ END_INSN(A)
129
+ }
130
+ INSN_ENTRY(B)
131
+ {
132
+ int i;
133
+ for (i = 0; i < (int)sizeof_array(month_names); i++) {
134
+ size_t l = strlen(month_names[i]);
135
+ if (strncasecmp(month_names[i], &str[si], l) == 0) {
136
+ si += l;
137
+ mon = (i % 12) + 1;
138
+ ADD_PC(1);
139
+ END_INSN(B)
140
+ }
141
+ }
142
+ fail();
143
+ }
144
+ INSN_ENTRY(C)
145
+ {
146
+ ADD_PC(1);
147
+ END_INSN(C)
148
+ }
149
+ INSN_ENTRY(D)
150
+ {
151
+ ADD_PC(1);
152
+ END_INSN(D)
153
+ }
154
+ INSN_ENTRY(E)
155
+ {
156
+ ADD_PC(1);
157
+ END_INSN(E)
158
+ }
159
+ INSN_ENTRY(F)
160
+ {
161
+ ADD_PC(1);
162
+ END_INSN(F)
163
+ }
164
+ INSN_ENTRY(G)
165
+ {
166
+ ADD_PC(1);
167
+ END_INSN(G)
168
+ }
169
+ INSN_ENTRY(H)
170
+ {
171
+ READ_DIGITS(hour, 2);
172
+ if (!valid_range_p(hour, 0, 23)) fail();
173
+ ADD_PC(1);
174
+ END_INSN(H)
175
+ }
176
+ INSN_ENTRY(I)
177
+ {
178
+ ADD_PC(1);
179
+ END_INSN(I)
180
+ }
181
+ INSN_ENTRY(L)
182
+ {
183
+ ADD_PC(1);
184
+ END_INSN(L)
185
+ }
186
+ INSN_ENTRY(M)
187
+ {
188
+ READ_DIGITS(min, 2);
189
+ if (!valid_range_p(min, 0, 59)) fail();
190
+ ADD_PC(1);
191
+ END_INSN(M)
192
+ }
193
+ INSN_ENTRY(N)
194
+ {
195
+ size_t l;
196
+ l = read_digits(&str[si], &nsec, 9);
197
+ if (!l) fail();
198
+ si += l;
199
+ for (; l < 9; l++) {
200
+ nsec *= 10;
201
+ }
202
+ ADD_PC(1);
203
+ END_INSN(N)
204
+ }
205
+ INSN_ENTRY(O)
206
+ {
207
+ ADD_PC(1);
208
+ END_INSN(O)
209
+ }
210
+ INSN_ENTRY(P)
211
+ {
212
+ ADD_PC(1);
213
+ END_INSN(P)
214
+ }
215
+ INSN_ENTRY(Q)
216
+ {
217
+ ADD_PC(1);
218
+ END_INSN(Q)
219
+ }
220
+ INSN_ENTRY(R)
221
+ {
222
+ ADD_PC(1);
223
+ END_INSN(R)
224
+ }
225
+ INSN_ENTRY(S)
226
+ {
227
+ READ_DIGITS(sec, 2);
228
+ if (!valid_range_p(sec, 0, 60)) fail();
229
+ ADD_PC(1);
230
+ END_INSN(S)
231
+ }
232
+ INSN_ENTRY(T)
233
+ {
234
+ ADD_PC(1);
235
+ END_INSN(T)
236
+ }
237
+ INSN_ENTRY(U)
238
+ {
239
+ ADD_PC(1);
240
+ END_INSN(U)
241
+ }
242
+ INSN_ENTRY(V)
243
+ {
244
+ ADD_PC(1);
245
+ END_INSN(V)
246
+ }
247
+ INSN_ENTRY(W)
248
+ {
249
+ ADD_PC(1);
250
+ END_INSN(W)
251
+ }
252
+ INSN_ENTRY(X)
253
+ {
254
+ ADD_PC(1);
255
+ END_INSN(X)
256
+ }
257
+ INSN_ENTRY(Y)
258
+ {
259
+ char c = str[si];
260
+ if (issign(c)) si++;
261
+ READ_DIGITS(year, 4);
262
+ if (c == '-') year *= -1;
263
+ ADD_PC(1);
264
+ END_INSN(Y)
265
+ }
266
+ INSN_ENTRY(Z)
267
+ {
268
+ ADD_PC(1);
269
+ END_INSN(Z)
270
+ }
271
+ INSN_ENTRY(a)
272
+ {
273
+ ADD_PC(1);
274
+ END_INSN(a)
275
+ }
276
+ INSN_ENTRY(c)
277
+ {
278
+ ADD_PC(1);
279
+ END_INSN(c)
280
+ }
281
+ INSN_ENTRY(d)
282
+ {
283
+ READ_DIGITS(mday, 2);
284
+ if (!valid_range_p(mday, 1, 31)) fail();
285
+ ADD_PC(1);
286
+ END_INSN(d)
287
+ }
288
+ INSN_ENTRY(g)
289
+ {
290
+ ADD_PC(1);
291
+ END_INSN(g)
292
+ }
293
+ INSN_ENTRY(j)
294
+ {
295
+ ADD_PC(1);
296
+ END_INSN(j)
297
+ }
298
+ INSN_ENTRY(l)
299
+ {
300
+ ADD_PC(1);
301
+ END_INSN(l)
302
+ }
303
+ INSN_ENTRY(m)
304
+ {
305
+ READ_DIGITS(mon, 2);
306
+ if (!valid_range_p(mon, 1, 12)) fail();
307
+ ADD_PC(1);
308
+ END_INSN(m)
309
+ }
310
+ INSN_ENTRY(n)
311
+ {
312
+ for (; si < slen && isspace(str[si]); si++) {
313
+ }
314
+ ADD_PC(1);
315
+ END_INSN(n)
316
+ }
317
+ INSN_ENTRY(p)
318
+ {
319
+ ADD_PC(1);
320
+ END_INSN(p)
321
+ }
322
+ INSN_ENTRY(r)
323
+ {
324
+ ADD_PC(1);
325
+ END_INSN(r)
326
+ }
327
+ INSN_ENTRY(s)
328
+ {
329
+ ADD_PC(1);
330
+ END_INSN(s)
331
+ }
332
+ INSN_ENTRY(t)
333
+ {
334
+ ADD_PC(1);
335
+ END_INSN(t)
336
+ }
337
+ INSN_ENTRY(u)
338
+ {
339
+ ADD_PC(1);
340
+ END_INSN(u)
341
+ }
342
+ INSN_ENTRY(v)
343
+ {
344
+ ADD_PC(1);
345
+ END_INSN(v)
346
+ }
347
+ INSN_ENTRY(w)
348
+ {
349
+ ADD_PC(1);
350
+ END_INSN(w)
351
+ }
352
+ INSN_ENTRY(x)
353
+ {
354
+ ADD_PC(1);
355
+ END_INSN(x)
356
+ }
357
+ INSN_ENTRY(y)
358
+ {
359
+ ADD_PC(1);
360
+ END_INSN(y)
361
+ }
362
+ INSN_ENTRY(z)
363
+ {
364
+ const char *p0 = str + si;
365
+ int r;
366
+ size_t len;
367
+ if (*p0 == 'z') {
368
+ gmtoff = 0;
369
+ ADD_PC(1);
370
+ END_INSN(z)
371
+ }
372
+ if (issign(*p0)) si++;
373
+ READ_DIGITS(r, 2);
374
+ gmtoff = r * 60;
375
+ if (str[si] == ':') si++;
376
+ len = read_digits(&str[si], &r, 2);
377
+ if (len) {
378
+ si += len;
379
+ gmtoff += r;
380
+ }
381
+ gmtoff *= 60;
382
+ if (*p0 == '-') gmtoff = -gmtoff;
383
+ ADD_PC(1);
384
+ END_INSN(z)
385
+ }
386
+ INSN_ENTRY(_25)
387
+ {
388
+ ADD_PC(1);
389
+ END_INSN(_25)
390
+ }
391
+ INSN_ENTRY(_2b)
392
+ {
393
+ ADD_PC(1);
394
+ END_INSN(_2b)
395
+ }
396
+ INSN_ENTRY(_3a)
397
+ {
398
+ ADD_PC(1);
399
+ END_INSN(_3a)
400
+ }
401
+ INSN_ENTRY(_60)
402
+ {
403
+ size_t v = (size_t)GET_OPERAND(1);
404
+ size_t fi = v & 0xFFFF;
405
+ size_t cnt = v >> 16;
406
+ if (memcmp(str + si, fmt + fi, cnt)) return Qnil;
407
+ pc += 2;
408
+ si += cnt;
409
+ END_INSN(_60)
410
+ }
411
+ INSN_ENTRY(_5f)
412
+ {
413
+ struct timespec ts;
414
+ struct tm tm;
415
+ time_t t;
416
+
417
+ /* get current time with timezone */
418
+ timespec_now(&ts);
419
+ {
420
+ static time_t ct;
421
+ static struct tm ctm;
422
+ static long cgmtoff;
423
+ static long cloff;
424
+ long off;
425
+ if (ct == ts.tv_sec) {
426
+ off = cgmtoff;
427
+ }
428
+ else {
429
+ ct = ts.tv_sec;
430
+ localtime_with_gmtoff_zone(&ct, &ctm, &off, NULL);
431
+ cloff = off;
432
+ cgmtoff = INT_MAX;
433
+ }
434
+ if (gmtoff == INT_MAX) {
435
+ gmtoff = cloff;
436
+ }
437
+ if (gmtoff != off) {
438
+ tm_add_offset(&ctm, gmtoff - off);
439
+ }
440
+ memcpy(&tm, &ctm, sizeof(struct tm));
441
+ cgmtoff = gmtoff;
442
+ }
443
+
444
+ /* overwrite time */
445
+ if (year != INT_MAX) {
446
+ tm.tm_year = year - 1900;
447
+ if (mon == -1) mon = 1;
448
+ setmonth:
449
+ tm.tm_mon = mon - 1;
450
+ if (mday == -1) mday = 1;
451
+ setmday:
452
+ tm.tm_mday = mday;
453
+ if (hour == -1) hour = 0;
454
+ sethour:
455
+ tm.tm_hour = hour;
456
+ if (min == -1) min = 0;
457
+ setmin:
458
+ tm.tm_min = min;
459
+ if (sec == -1) sec = 0;
460
+ tm.tm_sec = sec;
461
+ }
462
+ else {
463
+ if (mon != -1) goto setmonth;
464
+ if (mday != -1) goto setmday;
465
+ if (hour != -1) goto sethour;
466
+ if (min != -1) goto setmin;
467
+ if (sec != -1) tm.tm_sec = sec;
468
+ }
469
+
470
+ {
471
+ static time_t ct;
472
+ static struct tm cache;
473
+ /* struct tm to time_t */
474
+ if (ct && cache.tm_year == tm.tm_year &&
475
+ cache.tm_mon == tm.tm_mon && cache.tm_mday == tm.tm_mday) {
476
+ t = ct + (tm.tm_hour - cache.tm_hour) * 3600 +
477
+ (tm.tm_min - cache.tm_min) * 60 +
478
+ (tm.tm_sec - cache.tm_sec);
479
+ }
480
+ else {
481
+ ct = t = timegm_noleapsecond(&tm);
482
+ memcpy((void *)&cache, &tm, sizeof(struct tm));
483
+ }
484
+ t -= gmtoff;
485
+ }
486
+ tsp->tv_sec = t;
487
+ tsp->tv_nsec = nsec;
488
+ *gmtoffp = gmtoff;
489
+ return 0;
490
+ END_INSN(_5f)
491
+ }
492
+ END_INSNS_DISPATCH();
493
+
494
+ /* unreachable */
495
+ rb_bug("vm_eval: unreachable");
496
+ goto first;
497
+ }
498
+
499
+ void **
500
+ strptime_compile(const char *fmt, size_t flen)
501
+ {
502
+ size_t fi = 0;
503
+ char c;
504
+ void **isns0 = ALLOC_N(void *, flen + 2);
505
+ void **isns = isns0;
506
+ void **insns_address_table;
507
+ void *tmp;
508
+ strptime_exec0((void **)&insns_address_table, NULL, NULL, 0, NULL, NULL);
509
+
510
+ while (fi < flen) {
511
+ switch (fmt[fi]) {
512
+ case '%':
513
+ fi++;
514
+ c = fmt[fi];
515
+ switch (c) {
516
+ case 'B':
517
+ case 'H':
518
+ case 'M':
519
+ case 'N':
520
+ case 'S':
521
+ case 'Y':
522
+ case 'b':
523
+ case 'd':
524
+ case 'e':
525
+ case 'h':
526
+ case 'm':
527
+ case 'n':
528
+ case 'z':
529
+ tmp = insns_address_table[c - 'A'];
530
+ if (tmp) {
531
+ *isns++ = tmp;
532
+ fi++;
533
+ continue;
534
+ }
535
+ default: rb_raise(rb_eArgError, "invalid format"); break;
536
+ }
537
+ case ' ':
538
+ case '\t':
539
+ case '\n':
540
+ case '\v':
541
+ case '\f':
542
+ case '\r':
543
+ *isns++ = insns_address_table['n' - 'A'];
544
+ fi++;
545
+ break;
546
+ default: {
547
+ const char *p0 = fmt + fi, *p = p0, *pe = fmt + flen;
548
+ size_t v = fi;
549
+ while (p < pe && *p != '%' && !ISSPACE(*p))
550
+ p++;
551
+ v += (p - p0) << 16;
552
+ fi += p - p0;
553
+ *isns++ = insns_address_table['`' - 'A'];
554
+ *isns++ = (void *)v;
555
+ } break;
556
+ }
557
+ }
558
+ *isns++ = insns_address_table['_' - 'A'];
559
+ REALLOC_N(isns0, void *, isns - isns0);
560
+ return isns0;
561
+ }
562
+
563
+ struct strptime_object {
564
+ void **isns;
565
+ VALUE fmt;
566
+ };
567
+
568
+ static void
569
+ strptime_mark(void *ptr)
570
+ {
571
+ struct strptime_object *tobj = ptr;
572
+ rb_gc_mark(tobj->fmt);
573
+ }
574
+
575
+ static size_t
576
+ strptime_memsize(const void *tobj)
577
+ {
578
+ return sizeof(struct strptime_object);
579
+ }
580
+
581
+ static const rb_data_type_t strptime_data_type = {
582
+ "strptime",
583
+ {
584
+ strptime_mark, RUBY_TYPED_DEFAULT_FREE, strptime_memsize,
585
+ },
586
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
587
+ 0,
588
+ 0,
589
+ RUBY_TYPED_FREE_IMMEDIATELY
590
+ #endif
591
+ };
592
+
593
+ static VALUE
594
+ strptime_s_alloc(VALUE klass)
595
+ {
596
+ VALUE obj;
597
+ struct strptime_object *tobj;
598
+
599
+ obj = TypedData_Make_Struct(klass, struct strptime_object,
600
+ &strptime_data_type, tobj);
601
+
602
+ return obj;
603
+ }
604
+
605
+ static struct strptime_object *
606
+ get_strptimeval(VALUE obj)
607
+ {
608
+ struct strptime_object *tobj;
609
+ TypedData_Get_Struct(obj, struct strptime_object, &strptime_data_type,
610
+ tobj);
611
+ if (!STRPTIME_INIT_P(tobj)) {
612
+ rb_raise(rb_eTypeError, "uninitialized %" PRIsVALUE, rb_obj_class(obj));
613
+ }
614
+ return tobj;
615
+ }
616
+
617
+ static struct strptime_object *
618
+ get_new_strptimeval(VALUE obj)
619
+ {
620
+ struct strptime_object *tobj;
621
+ TypedData_Get_Struct(obj, struct strptime_object, &strptime_data_type,
622
+ tobj);
623
+ if (STRPTIME_INIT_P(tobj)) {
624
+ rb_raise(rb_eTypeError, "already initialized %" PRIsVALUE,
625
+ rb_obj_class(obj));
626
+ }
627
+ return tobj;
628
+ }
629
+
630
+ /*
631
+ * call-seq:
632
+ * Strptime.new(format) -> object
633
+ *
634
+ * returns parser object
635
+ */
636
+ static VALUE
637
+ strptime_init(VALUE self, VALUE fmt)
638
+ {
639
+ struct strptime_object *tobj;
640
+ void **isns;
641
+ StringValue(fmt);
642
+ TypedData_Get_Struct(self, struct strptime_object, &strptime_data_type,
643
+ tobj);
644
+ isns = strptime_compile(RSTRING_PTR(fmt), RSTRING_LEN(fmt));
645
+ tobj->isns = isns;
646
+ tobj->fmt = rb_str_new_frozen(fmt);
647
+ return self;
648
+ }
649
+
650
+ /* :nodoc: */
651
+ static VALUE
652
+ strptime_init_copy(VALUE copy, VALUE self)
653
+ {
654
+ struct strptime_object *tobj, *tcopy;
655
+
656
+ if (!OBJ_INIT_COPY(copy, self)) return copy;
657
+ GetStrptimeval(self, tobj);
658
+ GetNewStrptimeval(copy, tcopy);
659
+ MEMCPY(tcopy, tobj, struct strptime_object, 1);
660
+
661
+ return copy;
662
+ }
663
+
664
+ typedef uint64_t WIDEVALUE;
665
+ typedef WIDEVALUE wideval_t;
666
+ #ifndef PACKED_STRUCT_UNALIGNED
667
+ #define PACKED_STRUCT_UNALIGNED(x) x
668
+ #endif
669
+ PACKED_STRUCT_UNALIGNED(struct vtm {
670
+ VALUE year; /* 2000 for example. Integer. */
671
+ VALUE subsecx; /* 0 <= subsecx < TIME_SCALE. possibly Rational. */
672
+ VALUE utc_offset; /* -3600 as -01:00 for example. possibly Rational. */
673
+ const char *zone; /* "JST", "EST", "EDT", etc. */
674
+ uint16_t yday : 9; /* 1..366 */
675
+ uint8_t mon : 4; /* 1..12 */
676
+ uint8_t mday : 5; /* 1..31 */
677
+ uint8_t hour : 5; /* 0..23 */
678
+ uint8_t min : 6; /* 0..59 */
679
+ uint8_t sec : 6; /* 0..60 */
680
+ uint8_t wday : 3; /* 0:Sunday, 1:Monday, ..., 6:Saturday 7:init */
681
+ uint8_t isdst : 2; /* 0:StandardTime 1:DayLightSavingTime 3:init */
682
+ });
683
+ PACKED_STRUCT_UNALIGNED(struct time_object {
684
+ wideval_t timew; /* time_t value * TIME_SCALE. possibly Rational. */
685
+ struct vtm vtm;
686
+ uint8_t gmt : 3; /* 0:utc 1:localtime 2:fixoff 3:init */
687
+ uint8_t tm_got : 1;
688
+ });
689
+
690
+ /*
691
+ * call-seq:
692
+ * Strptime#exec(str) -> time
693
+ *
694
+ *
695
+ */
696
+ static VALUE
697
+ strptime_exec(VALUE self, VALUE str)
698
+ {
699
+ struct strptime_object *tobj;
700
+ int r, gmtoff = 0;
701
+ StringValue(str);
702
+ GetStrptimeval(self, tobj);
703
+ struct timespec ts;
704
+
705
+ r = strptime_exec0(tobj->isns, RSTRING_PTR(tobj->fmt), RSTRING_PTR(str),
706
+ RSTRING_LEN(str), &ts, &gmtoff);
707
+ if (r) rb_raise(rb_eArgError, "string doesn't match");
708
+ return rbtime_timespec_new(&ts, gmtoff);
709
+ }
710
+
711
+ /*
712
+ * call-seq:
713
+ * Strptime#execi(str) -> integer
714
+ *
715
+ * returns epoch as integer
716
+ */
717
+ static VALUE
718
+ strptime_execi(VALUE self, VALUE str)
719
+ {
720
+ struct strptime_object *tobj;
721
+ struct timespec ts;
722
+ int r, gmtoff = 0;
723
+ StringValue(str);
724
+ GetStrptimeval(self, tobj);
725
+
726
+ r = strptime_exec0(tobj->isns, RSTRING_PTR(tobj->fmt), RSTRING_PTR(str),
727
+ RSTRING_LEN(str), &ts, &gmtoff);
728
+ if (r) rb_raise(rb_eArgError, "string doesn't match");
729
+ return TIMET2NUM(ts.tv_sec);
730
+ }
731
+
732
+ /*
733
+ * call-seq:
734
+ * Strptime#source -> string
735
+ *
736
+ * returns source format string
737
+ */
738
+ static VALUE
739
+ strptime_source(VALUE self)
740
+ {
741
+ struct strptime_object *tobj;
742
+ GetStrptimeval(self, tobj);
743
+
744
+ return tobj->fmt;
745
+ }
746
+
747
+ /*
748
+ * Strptime is a faster way to parse time strings.
749
+ *
750
+ * parser = Strptime.new('%Y-%m-%dT%H:%M:%S%z')
751
+ * parser.exec('2015-12-25T12:34:56+09') #=> 2015-12-25 12:34:56 +09:00
752
+ * parser.execi('2015-12-25T12:34:56+09') #=> 1451014496
753
+ */
754
+ void
755
+ Init_strptime(void)
756
+ {
757
+ rb_cStrptime = rb_define_class("Strptime", rb_cObject);
758
+ rb_define_alloc_func(rb_cStrptime, strptime_s_alloc);
759
+ rb_define_method(rb_cStrptime, "initialize", strptime_init, 1);
760
+ rb_define_method(rb_cStrptime, "initialize_copy", strptime_init_copy, 1);
761
+ rb_define_method(rb_cStrptime, "exec", strptime_exec, 1);
762
+ rb_define_method(rb_cStrptime, "execi", strptime_execi, 1);
763
+ rb_define_method(rb_cStrptime, "source", strptime_source, 0);
764
+ }