summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--include/ruby/encoding.h3
-rw-r--r--io.c91
-rw-r--r--transcode.c6
4 files changed, 60 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index b83dde94ae..5155eb1e17 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Fri Dec 26 14:01:38 2008 Tanaka Akira <akr@fsij.org>
+
+ * io.c (fptr_finalize): close the IO object even if finish_writeconv or
+ flush is failed.
+ (finish_writeconv): don't raise. return errno or exception.
+ (finish_writeconv_arg): removed.
+ (finish_writeconv_sync): follow finish_writeconv change.
+
+ * transcode.c (rb_econv_make_exception): new function.
+
+ * include/ruby/encoding.h (rb_econv_make_exception): declared.
+
Thu Dec 25 20:57:01 2008 NARUSE, Yui <naruse@ruby-lang.org>
* transcode.c (str_transcode0): set encoding when String#encode was
diff --git a/include/ruby/encoding.h b/include/ruby/encoding.h
index 64bfff5944..6a808a58cb 100644
--- a/include/ruby/encoding.h
+++ b/include/ruby/encoding.h
@@ -248,6 +248,9 @@ const char *rb_econv_encoding_to_insert_output(rb_econv_t *ec);
/* raise an error if the last rb_econv_convert is error */
void rb_econv_check_error(rb_econv_t *ec);
+/* returns an exception object or nil */
+VALUE rb_econv_make_exception(rb_econv_t *ec);
+
int rb_econv_putbackable(rb_econv_t *ec);
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n);
diff --git a/io.c b/io.c
index 1287d94f5e..aaa20c6e99 100644
--- a/io.c
+++ b/io.c
@@ -3034,11 +3034,12 @@ rb_io_set_close_on_exec(VALUE io, VALUE arg)
#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
-static void
-finish_writeconv(rb_io_t *fptr, int noraise)
+static VALUE
+finish_writeconv(rb_io_t *fptr)
{
unsigned char *ds, *dp, *de;
rb_econv_result_t res;
+ VALUE err;
if (!fptr->wbuf) {
unsigned char buf[1024];
@@ -3058,104 +3059,90 @@ finish_writeconv(rb_io_t *fptr, int noraise)
ds += r;
}
if (rb_io_wait_writable(fptr->fd)) {
- if (!noraise)
- rb_io_check_closed(fptr);
- else if (fptr->fd < 0)
- return;
+ if (fptr->fd < 0)
+ return rb_exc_new3(rb_eIOError, rb_str_new_cstr("closed stream"));
goto retry;
}
- return;
- }
- if (!noraise) {
- rb_econv_check_error(fptr->writeconv);
- }
- if (res == econv_invalid_byte_sequence ||
- res == econv_incomplete_input ||
- res == econv_undefined_conversion) {
- break;
+ return INT2NUM(errno);
}
+ if (!NIL_P(err = rb_econv_make_exception(fptr->writeconv)))
+ return err;
}
- return;
+ return Qnil;
}
res = econv_destination_buffer_full;
while (res == econv_destination_buffer_full) {
if (fptr->wbuf_len == fptr->wbuf_capa) {
- if (io_fflush(fptr) < 0 && !noraise)
- rb_sys_fail(0);
+ if (io_fflush(fptr) < 0)
+ return INT2NUM(errno);
}
ds = dp = (unsigned char *)fptr->wbuf + fptr->wbuf_off + fptr->wbuf_len;
de = (unsigned char *)fptr->wbuf + fptr->wbuf_capa;
res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
fptr->wbuf_len += dp - ds;
- if (!noraise) {
- rb_econv_check_error(fptr->writeconv);
- }
- if (res == econv_invalid_byte_sequence ||
- res == econv_incomplete_input ||
- res == econv_undefined_conversion) {
- break;
- }
+ if (!NIL_P(err = rb_econv_make_exception(fptr->writeconv)))
+ return err;
}
-
+ return Qnil;
}
-struct finish_writeconv_arg {
- rb_io_t *fptr;
- int noraise;
-};
-
static VALUE
finish_writeconv_sync(VALUE arg)
{
- struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
- finish_writeconv(p->fptr, p->noraise);
- return Qnil;
+ rb_io_t *fptr = (rb_io_t *)arg;
+ return finish_writeconv(fptr);
}
static void
fptr_finalize(rb_io_t *fptr, int noraise)
{
- int close_failure = 0;
+ VALUE err = Qnil;
if (fptr->writeconv) {
if (fptr->write_lock) {
- struct finish_writeconv_arg arg;
- arg.fptr = fptr;
- arg.noraise = noraise;
- rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
+ err = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)fptr);
}
else {
- finish_writeconv(fptr, noraise);
+ err = finish_writeconv(fptr);
}
}
if (fptr->wbuf_len) {
- if (io_fflush(fptr) < 0 && !noraise)
- rb_sys_fail(0);
+ if (io_fflush(fptr) < 0 && NIL_P(err))
+ err = INT2NUM(errno);
}
- if (IS_PREP_STDIO(fptr) ||
- fptr->fd <= 2) {
- return;
+ if (IS_PREP_STDIO(fptr) || fptr->fd <= 2) {
+ goto check_err;
}
if (fptr->stdio_file) {
/* fptr->stdio_file is deallocated anyway
* even if fclose failed. */
- if (fclose(fptr->stdio_file) < 0)
- close_failure = 1;
+ if (fclose(fptr->stdio_file) < 0 && NIL_P(err))
+ err = INT2NUM(errno);
}
else if (0 <= fptr->fd) {
/* fptr->fd may be closed even if close fails.
* POSIX doesn't specify it.
* We assumes it is closed. */
- if (close(fptr->fd) < 0)
- close_failure = 1;
+ if (close(fptr->fd) < 0 && NIL_P(err))
+ err = INT2NUM(errno);
}
fptr->fd = -1;
fptr->stdio_file = 0;
fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
- if (close_failure && !noraise) {
- rb_sys_fail_path(fptr->pathv);
+
+ check_err:
+ if (!NIL_P(err) && !noraise) {
+ switch(TYPE(err)) {
+ case T_FIXNUM:
+ case T_BIGNUM:
+ errno = NUM2INT(err);
+ rb_sys_fail_path(fptr->pathv);
+
+ default:
+ rb_exc_raise(err);
+ }
}
}
diff --git a/transcode.c b/transcode.c
index 7cdda7b7b2..72e26f6df2 100644
--- a/transcode.c
+++ b/transcode.c
@@ -3854,6 +3854,12 @@ econv_set_replacement(VALUE self, VALUE arg)
return arg;
}
+VALUE
+rb_econv_make_exception(rb_econv_t *ec)
+{
+ return make_econv_exception(ec);
+}
+
void
rb_econv_check_error(rb_econv_t *ec)
{