summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-11-18 13:02:14 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-11-18 13:02:14 +0000
commit4c6eda226aeee4896c3dfc1ca6c2cacfc9788d27 (patch)
tree34a6346479e74c7268d7b7f0d20011b336b8c986 /io.c
parent817f503001e1e802f8129a5a52cf378f2042c24d (diff)
* io.c (fill_cbuf): extracted from more_char.
(io_shift_cbuf): fix memmove condition. (read_all): use fill_cbuf directly to avoid ECONV_AFTER_OUTPUT. [ruby-dev:39708] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25845 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'io.c')
-rw-r--r--io.c66
1 files changed, 41 insertions, 25 deletions
diff --git a/io.c b/io.c
index 21188eb17d..5c10c69930 100644
--- a/io.c
+++ b/io.c
@@ -1582,17 +1582,22 @@ make_readconv(rb_io_t *fptr, int size)
}
}
-static int
-more_char(rb_io_t *fptr)
+#define MORE_CHAR_CBUF_FULL Qtrue
+#define MORE_CHAR_FINISHED Qnil
+static VALUE
+fill_cbuf(rb_io_t *fptr, int ec_flags)
{
const unsigned char *ss, *sp, *se;
unsigned char *ds, *dp, *de;
rb_econv_result_t res;
int putbackable;
int cbuf_len0;
+ VALUE exc;
+
+ ec_flags |= ECONV_PARTIAL_INPUT;
if (fptr->cbuf_len == fptr->cbuf_capa)
- return 0; /* cbuf full */
+ return MORE_CHAR_CBUF_FULL; /* cbuf full */
if (fptr->cbuf_len == 0)
fptr->cbuf_off = 0;
else if (fptr->cbuf_off + fptr->cbuf_len == fptr->cbuf_capa) {
@@ -1607,7 +1612,7 @@ more_char(rb_io_t *fptr)
se = sp + fptr->rbuf_len;
ds = dp = (unsigned char *)fptr->cbuf + fptr->cbuf_off + fptr->cbuf_len;
de = (unsigned char *)fptr->cbuf + fptr->cbuf_capa;
- res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ECONV_PARTIAL_INPUT|ECONV_AFTER_OUTPUT);
+ res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
fptr->rbuf_off += (int)(sp - ss);
fptr->rbuf_len -= (int)(sp - ss);
fptr->cbuf_len += (int)(dp - ds);
@@ -1619,13 +1624,15 @@ more_char(rb_io_t *fptr)
fptr->rbuf_len += putbackable;
}
- rb_econv_check_error(fptr->readconv);
+ exc = rb_econv_make_exception(fptr->readconv);
+ if (!NIL_P(exc))
+ return exc;
if (cbuf_len0 != fptr->cbuf_len)
- return 0;
+ return MORE_CHAR_CBUF_FULL;
if (res == econv_finished) {
- return -1;
+ return MORE_CHAR_FINISHED;
}
if (res == econv_source_buffer_empty) {
@@ -1645,6 +1652,16 @@ more_char(rb_io_t *fptr)
}
static VALUE
+more_char(rb_io_t *fptr)
+{
+ VALUE v;
+ v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
+ if (v != MORE_CHAR_CBUF_FULL && v != MORE_CHAR_FINISHED)
+ rb_exc_raise(v);
+ return v;
+}
+
+static VALUE
io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
{
VALUE str;
@@ -1665,7 +1682,7 @@ io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
/* xxx: set coderange */
if (fptr->cbuf_len == 0)
fptr->cbuf_off = 0;
- if (fptr->cbuf_off < fptr->cbuf_capa/2) {
+ else if (fptr->cbuf_capa/2 < fptr->cbuf_off) {
memmove(fptr->cbuf, fptr->cbuf+fptr->cbuf_off, fptr->cbuf_len);
fptr->cbuf_off = 0;
}
@@ -1686,21 +1703,19 @@ read_all(rb_io_t *fptr, long siz, VALUE str)
else rb_str_set_len(str, 0);
make_readconv(fptr, 0);
while (1) {
- int fin, state = 0;
-
- if (fptr->cbuf_len > fptr->cbuf_capa / 2) {
+ VALUE v;
+ if (fptr->cbuf_len) {
io_shift_cbuf(fptr, fptr->cbuf_len, &str);
}
-
- fin = rb_protect((VALUE (*)(VALUE))more_char, (VALUE)fptr, &state);
- if (fin == -1 || state != 0) {
- if (fptr->cbuf_len) {
- io_shift_cbuf(fptr, fptr->cbuf_len, &str);
- }
- if (state != 0) {
- rb_jump_tag(state);
- }
- clear_readconv(fptr);
+ v = fill_cbuf(fptr, 0);
+ if (v != MORE_CHAR_CBUF_FULL && v != MORE_CHAR_FINISHED) {
+ if (fptr->cbuf_len) {
+ io_shift_cbuf(fptr, fptr->cbuf_len, &str);
+ }
+ rb_exc_raise(v);
+ }
+ if (v == MORE_CHAR_FINISHED) {
+ clear_readconv(fptr);
return io_enc_str(str, fptr);
}
}
@@ -2181,7 +2196,7 @@ appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
}
}
- } while (more_char(fptr) != -1);
+ } while (more_char(fptr) != MORE_CHAR_FINISHED);
clear_readconv(fptr);
*lp = limit;
return EOF;
@@ -2695,7 +2710,8 @@ io_getc(rb_io_t *fptr, rb_encoding *enc)
}
}
- if (more_char(fptr) == -1) {
+ if (more_char(fptr) == MORE_CHAR_FINISHED) {
+ clear_readconv(fptr);
if (fptr->cbuf_len == 0)
return Qnil;
/* return an incomplete character just before EOF */
@@ -2830,8 +2846,8 @@ rb_io_each_codepoint(VALUE io)
rb_raise(rb_eIOError, "too long character");
}
}
- if (more_char(fptr) == -1) {
- clear_readconv(fptr);
+ if (more_char(fptr) == MORE_CHAR_FINISHED) {
+ clear_readconv(fptr);
/* ignore an incomplete character before EOF */
return io;
}