Skip to content

Commit c500744

Browse files
committed
Preserve input encoding when parsing time zones
Pass the input encoding through `date__strptime` so non-ASCII trailing data is treated as a parse failure instead of raising an encoding error. Fixes #179.
1 parent 2140246 commit c500744

3 files changed

Lines changed: 23 additions & 28 deletions

File tree

‎ext/date/date_core.c‎

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4515,7 +4515,8 @@ d_new_by_frags(VALUE klass, VALUE hash, VALUE sg)
45154515
}
45164516

45174517
VALUE date__strptime(const char *str, size_t slen,
4518-
const char *fmt, size_t flen, VALUE hash);
4518+
const char *fmt, size_t flen,
4519+
VALUE hash, rb_encoding *enc);
45194520

45204521
static VALUE
45214522
date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
@@ -4524,6 +4525,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
45244525
VALUE vstr, vfmt, hash;
45254526
const char *str, *fmt;
45264527
size_t slen, flen;
4528+
rb_encoding *enc;
45274529

45284530
rb_scan_args(argc, argv, "11", &vstr, &vfmt);
45294531

@@ -4537,33 +4539,18 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
45374539
if (argc < 2) {
45384540
fmt = default_fmt;
45394541
flen = strlen(default_fmt);
4542+
enc = rb_enc_get(vstr);
45404543
}
45414544
else {
45424545
if (!rb_enc_str_asciicompat_p(vfmt))
45434546
rb_raise(rb_eArgError,
45444547
"format should have ASCII compatible encoding");
4548+
enc = rb_enc_check(vstr, vfmt);
45454549
fmt = RSTRING_PTR(vfmt);
45464550
flen = RSTRING_LEN(vfmt);
45474551
}
45484552
hash = rb_hash_new();
4549-
if (NIL_P(date__strptime(str, slen, fmt, flen, hash)))
4550-
return Qnil;
4551-
4552-
{
4553-
VALUE zone = ref_hash("zone");
4554-
VALUE left = ref_hash("leftover");
4555-
4556-
if (!NIL_P(zone)) {
4557-
rb_enc_copy(zone, vstr);
4558-
set_hash("zone", zone);
4559-
}
4560-
if (!NIL_P(left)) {
4561-
rb_enc_copy(left, vstr);
4562-
set_hash("leftover", left);
4563-
}
4564-
}
4565-
4566-
return hash;
4553+
return date__strptime(str, slen, fmt, flen, hash, enc);
45674554
}
45684555

45694556
/*

‎ext/date/date_strptime.c‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ valid_range_p(VALUE v, int a, int b)
144144
do { \
145145
size_t l; \
146146
l = date__strptime_internal(&str[si], slen - si, \
147-
fmt, sizeof fmt - 1, hash); \
147+
fmt, sizeof fmt - 1, hash, enc); \
148148
if (fail_p()) \
149149
return 0; \
150150
si += l; \
@@ -160,7 +160,8 @@ head_match_p(size_t len, const char *name, const char *str, size_t slen, size_t
160160

161161
static size_t
162162
date__strptime_internal(const char *str, size_t slen,
163-
const char *fmt, size_t flen, VALUE hash)
163+
const char *fmt, size_t flen,
164+
VALUE hash, rb_encoding *enc)
164165
{
165166
size_t si, fi;
166167
int c;
@@ -597,15 +598,14 @@ date__strptime_internal(const char *str, size_t slen,
597598

598599
b = rb_backref_get();
599600
rb_match_busy(b);
600-
m = f_match(pat, rb_usascii_str_new(&str[si], slen - si));
601+
m = f_match(pat, rb_enc_str_new(&str[si], slen - si, enc));
601602

602603
if (!NIL_P(m)) {
603-
VALUE s, l, o;
604+
VALUE s, o;
604605

605606
s = rb_reg_nth_match(1, m);
606-
l = f_end(m, INT2FIX(0));
607607
o = date_zone_to_diff(s);
608-
si += NUM2LONG(l);
608+
si += RMATCH_REGS(m)->end[0];
609609
set_hash("zone", s);
610610
set_hash("offset", o);
611611
rb_backref_set(b);
@@ -654,20 +654,21 @@ date__strptime_internal(const char *str, size_t slen,
654654

655655
VALUE
656656
date__strptime(const char *str, size_t slen,
657-
const char *fmt, size_t flen, VALUE hash)
657+
const char *fmt, size_t flen,
658+
VALUE hash, rb_encoding *enc)
658659
{
659660
size_t si;
660661
VALUE cent, merid;
661662

662-
si = date__strptime_internal(str, slen, fmt, flen, hash);
663+
si = date__strptime_internal(str, slen, fmt, flen, hash, enc);
663664

664665
if (fail_p())
665666
return Qnil;
666667

667668
if (slen > si) {
668669
VALUE s;
669670

670-
s = rb_usascii_str_new(&str[si], slen - si);
671+
s = rb_enc_str_new(&str[si], slen - si, enc);
671672
set_hash("leftover", s);
672673
}
673674

‎test/date/test_date_strptime.rb‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,4 +533,11 @@ def to_str
533533
assert_equal(6, d[:mon])
534534
assert_equal(1, d[:mday])
535535
end
536+
537+
def test_nonascii_string
538+
nonalpha = "\u{2600 fe0f}"
539+
s = "2011-10-05T22:26:12#{nonalpha}"
540+
541+
assert_nil(DateTime._strptime(s))
542+
end
536543
end

0 commit comments

Comments
 (0)