* ext/zlib/zlib.c (gzreader_gets): support optional length

parameter.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@30341 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2010-12-25 02:02:55 +00:00
Родитель aeb8d7f5e5
Коммит 91c6ba2333
3 изменённых файлов: 125 добавлений и 16 удалений

Просмотреть файл

@ -1,4 +1,7 @@
Sat Dec 25 10:59:12 2010 Nobuyoshi Nakada <nobu@ruby-lang.org> Sat Dec 25 11:02:52 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/zlib/zlib.c (gzreader_gets): support optional length
parameter.
* ext/zlib/zlib.c (gzfile_read, gzfile_readpartial): length should * ext/zlib/zlib.c (gzfile_read, gzfile_readpartial): length should
be long. be long.

Просмотреть файл

@ -2204,15 +2204,13 @@ gzfile_newstr(struct gzfile *gz, VALUE str)
gz->ecflags, gz->ecopts); gz->ecflags, gz->ecopts);
} }
static VALUE static long
gzfile_read(struct gzfile *gz, long len) gzfile_fill(struct gzfile *gz, long len)
{ {
VALUE dst;
if (len < 0) if (len < 0)
rb_raise(rb_eArgError, "negative length %ld given", len); rb_raise(rb_eArgError, "negative length %ld given", len);
if (len == 0) if (len == 0)
return rb_str_new(0, 0); return 0;
while (!ZSTREAM_IS_FINISHED(&gz->z) && gz->z.buf_filled < len) { while (!ZSTREAM_IS_FINISHED(&gz->z) && gz->z.buf_filled < len) {
gzfile_read_more(gz); gzfile_read_more(gz);
} }
@ -2220,9 +2218,19 @@ gzfile_read(struct gzfile *gz, long len)
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) { if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
gzfile_check_footer(gz); gzfile_check_footer(gz);
} }
return Qnil; return -1;
} }
return len < gz->z.buf_filled ? len : gz->z.buf_filled;
}
static VALUE
gzfile_read(struct gzfile *gz, long len)
{
VALUE dst;
len = gzfile_fill(gz, len);
if (len == 0) return rb_str_new(0, 0);
if (len < 0) return Qnil;
dst = zstream_shift_buffer(&gz->z, len); dst = zstream_shift_buffer(&gz->z, len);
gzfile_calc_crc(gz, dst); gzfile_calc_crc(gz, dst);
return dst; return dst;
@ -3351,6 +3359,27 @@ rscheck(const char *rsptr, long rslen, VALUE rs)
rb_raise(rb_eRuntimeError, "rs modified"); rb_raise(rb_eRuntimeError, "rs modified");
} }
static long
gzreader_charboundary(struct gzfile *gz, long n)
{
char *s = RSTRING_PTR(gz->z.buf);
char *e = s + gz->z.buf_filled;
char *p = rb_enc_left_char_head(s, s + n, e, gz->enc);
long l = p - s;
if (l < n) {
n = rb_enc_precise_mbclen(p, e, gz->enc);
if (MBCLEN_NEEDMORE_P(n)) {
if ((l = gzfile_fill(gz, l + MBCLEN_NEEDMORE_LEN(n))) > 0) {
return l;
}
}
else if (MBCLEN_CHARFOUND_P(n)) {
return l + MBCLEN_CHARFOUND_LEN(n);
}
}
return n;
}
static VALUE static VALUE
gzreader_gets(int argc, VALUE *argv, VALUE obj) gzreader_gets(int argc, VALUE *argv, VALUE obj)
{ {
@ -3359,24 +3388,57 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
VALUE dst; VALUE dst;
const char *rsptr; const char *rsptr;
char *p, *res; char *p, *res;
long rslen, n; long rslen, n, limit = -1;
int rspara; int rspara;
rb_encoding *enc = gz->enc;
int maxlen = rb_enc_mbmaxlen(enc);
if (argc == 0) { if (argc == 0) {
rs = rb_rs; rs = rb_rs;
} }
else { else {
rb_scan_args(argc, argv, "1", &rs); VALUE lim, tmp;
if (!NIL_P(rs)) {
Check_Type(rs, T_STRING); rb_scan_args(argc, argv, "11", &rs, &lim);
if (!NIL_P(lim)) {
if (!NIL_P(rs)) StringValue(rs);
}
else if (!NIL_P(rs)) {
tmp = rb_check_string_type(rs);
if (NIL_P(tmp)) {
lim = rs;
rs = rb_rs;
}
else {
rs = tmp;
}
}
if (!NIL_P(lim)) {
limit = NUM2LONG(lim);
if (limit == 0) return rb_str_new(0,0);
} }
} }
if (NIL_P(rs)) { if (NIL_P(rs)) {
dst = gzfile_read_all(gz); if (limit < 0) {
if (RSTRING_LEN(dst) != 0) gz->lineno++; dst = gzfile_read_all(gz);
else if (RSTRING_LEN(dst) == 0) return Qnil;
}
else if ((n = gzfile_fill(gz, limit)) <= 0) {
return Qnil; return Qnil;
}
else {
if (maxlen > 1 && n >= limit && !GZFILE_IS_FINISHED(gz)) {
n = gzreader_charboundary(gz, n);
}
else {
n = limit;
}
dst = zstream_shift_buffer(&gz->z, n);
gzfile_calc_crc(gz, dst);
dst = gzfile_newstr(gz, dst);
}
gz->lineno++;
return dst; return dst;
} }
@ -3405,15 +3467,22 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
p = RSTRING_PTR(gz->z.buf); p = RSTRING_PTR(gz->z.buf);
n = rslen; n = rslen;
for (;;) { for (;;) {
long filled;
if (n > gz->z.buf_filled) { if (n > gz->z.buf_filled) {
if (ZSTREAM_IS_FINISHED(&gz->z)) break; if (ZSTREAM_IS_FINISHED(&gz->z)) break;
gzfile_read_more(gz); gzfile_read_more(gz);
p = RSTRING_PTR(gz->z.buf) + n - rslen; p = RSTRING_PTR(gz->z.buf) + n - rslen;
} }
if (!rspara) rscheck(rsptr, rslen, rs); if (!rspara) rscheck(rsptr, rslen, rs);
res = memchr(p, rsptr[0], (gz->z.buf_filled - n + 1)); filled = gz->z.buf_filled;
if (limit > 0 && filled >= limit) {
filled = limit;
}
res = memchr(p, rsptr[0], (filled - n + 1));
if (!res) { if (!res) {
n = gz->z.buf_filled + 1; n = filled;
if (limit > 0 && filled >= limit) break;
n++;
} else { } else {
n += (long)(res - p); n += (long)(res - p);
p = res; p = res;
@ -3421,6 +3490,9 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
p++, n++; p++, n++;
} }
} }
if (maxlen > 1 && n == limit && (gz->z.buf_filled > n || !ZSTREAM_IS_FINISHED(&gz->z))) {
n = gzreader_charboundary(gz, n);
}
gz->lineno++; gz->lineno++;
dst = gzfile_read(gz, n); dst = gzfile_read(gz, n);

Просмотреть файл

@ -588,6 +588,40 @@ if defined? Zlib
Zlib::GzipReader.open(t.path) do |f| Zlib::GzipReader.open(t.path) do |f|
assert_equal("foo\nbar\nbaz\n", f.gets(nil)) assert_equal("foo\nbar\nbaz\n", f.gets(nil))
end end
Zlib::GzipReader.open(t.path) do |f|
assert_equal("foo\n", f.gets(10))
assert_equal("ba", f.gets(2))
assert_equal("r\nb", f.gets(nil, 3))
assert_equal("az\n", f.gets(nil, 10))
assert_nil(f.gets)
end
end
def test_gets2
t = Tempfile.new("test_zlib_gzip_reader_gets2")
t.close
ustrs = %W"\u{3042 3044 3046}\n \u{304b 304d 304f}\n \u{3055 3057 3059}\n"
Zlib::GzipWriter.open(t.path) {|gz| gz.print(*ustrs) }
Zlib::GzipReader.open(t.path, encoding: "UTF-8") do |f|
assert_equal(ustrs[0], f.gets)
assert_equal(ustrs[1], f.gets)
assert_equal(ustrs[2], f.gets)
assert_nil(f.gets)
end
Zlib::GzipReader.open(t.path, encoding: "UTF-8") do |f|
assert_equal(ustrs.join(''), f.gets(nil))
end
Zlib::GzipReader.open(t.path, encoding: "UTF-8") do |f|
assert_equal(ustrs[0], f.gets(20))
assert_equal(ustrs[1][0,2], f.gets(5))
assert_equal(ustrs[1][2..-1]+ustrs[2][0,1], f.gets(nil, 5))
assert_equal(ustrs[2][1..-1], f.gets(nil, 20))
assert_nil(f.gets)
end
end end
def test_readline def test_readline