[macruby-changes] [2059] MacRuby/branches/experimental/io.c
source_changes at macosforge.org
source_changes at macosforge.org
Thu Jul 23 18:20:20 PDT 2009
Revision: 2059
http://trac.macosforge.org/projects/ruby/changeset/2059
Author: lsansonetti at apple.com
Date: 2009-07-23 18:20:20 -0700 (Thu, 23 Jul 2009)
Log Message:
-----------
fixing a bunch of IO bugs
Modified Paths:
--------------
MacRuby/branches/experimental/io.c
Modified: MacRuby/branches/experimental/io.c
===================================================================
--- MacRuby/branches/experimental/io.c 2009-07-23 00:54:23 UTC (rev 2058)
+++ MacRuby/branches/experimental/io.c 2009-07-24 01:20:20 UTC (rev 2059)
@@ -79,6 +79,12 @@
return tmp;
}
+static inline VALUE
+rb_io_get_io(VALUE io)
+{
+ return rb_convert_type(io, T_FILE, "IO", "to_io");
+}
+
static int
convert_mode_string_to_fmode(VALUE rstr)
{
@@ -280,6 +286,31 @@
return s == kCFStreamStatusNotOpen || s == kCFStreamStatusClosed;
}
+static bool
+rb_io_is_readable(rb_io_t *io_struct)
+{
+ return !(rb_io_is_closed_for_reading(io_struct));
+}
+
+static bool
+rb_io_is_writable(rb_io_t *io_struct)
+{
+ return !(rb_io_is_closed_for_writing(io_struct));
+}
+
+static int
+rb_io_calculate_mode_flags(rb_io_t *io_struct)
+{
+ int flags = 0;
+ if (rb_io_is_readable(io_struct)) {
+ flags |= FMODE_READABLE;
+ }
+ if (rb_io_is_writable(io_struct)) {
+ flags |= FMODE_WRITABLE;
+ }
+ return flags;
+}
+
static VALUE
io_alloc(VALUE klass, SEL sel)
{
@@ -329,6 +360,10 @@
break;
}
+ if (stdio != 0) {
+ should_close_streams = false;
+ }
+
if (read) {
if (stdio != 0) {
GC_WB(&io_struct->readStream, ExtractIOStruct(stdio)->readStream);
@@ -590,12 +625,14 @@
}
// TODO: make this work with IO::SEEK_CUR, SEEK_END, etc.
if (CFReadStreamGetStatus(io_struct->readStream) == kCFStreamStatusAtEnd) {
+#if 0 // this doesn't work...
// Terrible hack to work around the fact that CFReadStreams, once they
// reach EOF, are permanently exhausted even if we set the offset.
GC_WB(&io_struct->readStream,
_CFReadStreamCreateFromFileDescriptor(NULL, io_struct->fd));
CFReadStreamOpen(io_struct->readStream);
CFMakeCollectable(io_struct->readStream);
+#endif
}
rb_io_read_stream_set_offset(io_struct->readStream, NUM2OFFT(offset));
return INT2FIX(0);
@@ -957,7 +994,7 @@
CFDataIncreaseLength(data, BUFSIZE);
UInt8 *b = CFDataGetMutableBytePtr(data) + original_position
+ bytes_read;
- long last_read = rb_io_read_internal(io_struct, b, BUFSIZE);
+ const long last_read = rb_io_read_internal(io_struct, b, BUFSIZE);
bytes_read += last_read;
if (last_read < BUFSIZE) {
break;
@@ -1177,22 +1214,21 @@
static VALUE
io_readpartial(VALUE io, SEL sel, int argc, VALUE *argv)
{
- VALUE maxlen, buffer;
- rb_scan_args(argc, argv, "11", &maxlen, &buffer);
- if (FIX2INT(maxlen) == 0) {
- return rb_str_new2("");
- }
- else if (FIX2INT(maxlen) < 0) {
- rb_raise(rb_eArgError, "negative numbers not valid");
- }
- VALUE read_data = io_read(io, sel, argc, argv);
- if (NIL_P(read_data)) {
- rb_eof_error();
- }
- return read_data;
+ VALUE maxlen, buffer;
+ rb_scan_args(argc, argv, "11", &maxlen, &buffer);
+ if (FIX2INT(maxlen) == 0) {
+ return rb_str_new2("");
+ }
+ else if (FIX2INT(maxlen) < 0) {
+ rb_raise(rb_eArgError, "negative numbers not valid");
+ }
+ VALUE read_data = io_read(io, sel, argc, argv);
+ if (NIL_P(read_data)) {
+ rb_eof_error();
+ }
+ return read_data;
}
-
/*
* call-seq:
* ios.gets(sep=$/) => string or nil
@@ -1325,7 +1361,7 @@
rb_io_lineno(VALUE io, SEL sel)
{
rb_io_t *io_s = ExtractIOStruct(io);
- rb_io_assert_open(io_s);
+ rb_io_assert_open(io_s);
return INT2FIX(io_s->lineno);
}
@@ -1350,12 +1386,11 @@
rb_io_set_lineno(VALUE io, SEL sel, VALUE line_no)
{
rb_io_t *io_s = ExtractIOStruct(io);
- rb_io_assert_open(io_s);
- line_no = rb_check_to_integer(line_no, "to_int");
- if (NIL_P(line_no))
- {
- rb_raise(rb_eTypeError, "lineno's argument must be coercable to integer");
- }
+ rb_io_assert_open(io_s);
+ line_no = rb_check_to_integer(line_no, "to_int");
+ if (NIL_P(line_no)) {
+ rb_raise(rb_eTypeError, "lineno's argument must be coercable to integer");
+ }
io_s->lineno = FIX2INT(line_no);
return line_no;
}
@@ -2267,14 +2302,25 @@
}
static VALUE
+f_open_body(VALUE io)
+{
+ return rb_vm_yield(1, &io);
+}
+
+static VALUE
+f_open_ensure(VALUE io)
+{
+ rb_io_close_m(io, 0);
+ return Qnil;
+}
+
+static VALUE
rb_f_open(VALUE klass, SEL sel, int argc, VALUE *argv)
{
VALUE io = rb_class_new_instance(argc, argv, rb_cFile);
io = rb_file_open(io, argc, argv);
if (rb_block_given_p()) {
- VALUE ret = rb_vm_yield(1, &io);
- rb_io_close_m(io, 0);
- return ret;
+ return rb_ensure(f_open_body, io, f_open_ensure, io);
}
return io;
}
@@ -2314,6 +2360,24 @@
* f2.readlines[0] #=> "This is line one\n"
*/
+static void
+io_replace_streams(int fd, rb_io_t *dest, rb_io_t *origin)
+{
+ prepare_io_from_fd(dest, fd, rb_io_calculate_mode_flags(origin),
+ origin->should_close_streams);
+
+ if (origin->ungetc_buf_len > 0) {
+ GC_WB(&dest->ungetc_buf, xmalloc(origin->ungetc_buf_len));
+ memcpy(dest->ungetc_buf, origin->ungetc_buf,
+ origin->ungetc_buf_len);
+ }
+ else {
+ dest->ungetc_buf = NULL;
+ }
+ dest->ungetc_buf_len = origin->ungetc_buf_len;
+ dest->ungetc_buf_pos = origin->ungetc_buf_pos;
+}
+
static VALUE
rb_io_reopen(VALUE io, SEL sel, int argc, VALUE *argv)
{
@@ -2336,11 +2400,41 @@
GC_WB(&io_s->path, path_or_io);
}
else {
- // reassociate it with the stream given in the other io
- // This is too simplistic.
+ // Reassociate it with a duplicate of the stream given
+ path_or_io = rb_io_get_io(path_or_io);
rb_io_t *other = ExtractIOStruct(path_or_io);
rb_io_assert_open(other);
- GC_WB(&RFILE(io)->fptr, other);
+ if (io_s == other) {
+ return io;
+ }
+
+ if (io_s->fd == -1) {
+ rb_raise(rb_eRuntimeError,
+ "cannot reopen non file descriptor based IO");
+ }
+ if (other->fd == -1) {
+ rb_raise(rb_eRuntimeError,
+ "cannot reopen from non file descriptor based IO");
+ }
+
+ if (io_s->should_close_streams) {
+ io_struct_close(io_s, true, true);
+ }
+ else {
+ if (io_s->readStream != NULL) {
+ CFRetain(io_s->readStream);
+ }
+ if (io_s->writeStream != NULL) {
+ CFRetain(io_s->writeStream);
+ }
+ }
+ int fd = dup2(other->fd, io_s->fd);
+ if (fd < 0) {
+ rb_sys_fail("dup2() failed");
+ }
+ io_replace_streams(fd, io_s, other);
+
+ *(VALUE *)io = *(VALUE *)path_or_io;
}
return io;
}
@@ -2349,30 +2443,24 @@
static VALUE
rb_io_init_copy(VALUE dest, SEL sel, VALUE origin)
{
+ origin = rb_io_get_io(origin);
rb_io_t *dest_io = ExtractIOStruct(dest);
rb_io_t *origin_io = ExtractIOStruct(origin);
- GC_WB(&dest_io->readStream, origin_io->readStream);
- GC_WB(&dest_io->writeStream, origin_io->writeStream);
+ if (dest_io == origin_io) {
+ return dest;
+ }
- dest_io->fd = origin_io->fd;
- dest_io->pipe = origin_io->pipe;
- GC_WB(&dest_io->path, origin_io->path);
- dest_io->pid = origin_io->pid;
- dest_io->lineno = origin_io->lineno;
- dest_io->sync = origin_io->sync;
- dest_io->should_close_streams = origin_io->should_close_streams;
-
- if (origin_io->ungetc_buf_len > 0) {
- GC_WB(&dest_io->ungetc_buf, xmalloc(origin_io->ungetc_buf_len));
- memcpy(dest_io->ungetc_buf, origin_io->ungetc_buf,
- origin_io->ungetc_buf_len);
+ if (origin_io->fd == -1) {
+ rb_raise(rb_eRuntimeError,
+ "cannot copy from non file descriptor based IO");
}
- else {
- dest_io->ungetc_buf = NULL;
+
+ int fd = dup(origin_io->fd);
+ if (fd < 0) {
+ rb_sys_fail("dup() failed");
}
- dest_io->ungetc_buf_len = origin_io->ungetc_buf_len;
- dest_io->ungetc_buf_pos = origin_io->ungetc_buf_pos;
+ io_replace_streams(fd, dest_io, origin_io);
return dest;
}
@@ -3228,136 +3316,123 @@
static int
build_fd_set_from_io_array(fd_set* set, VALUE arr)
{
- int max_fd = 0;
- FD_ZERO(set);
- if (!NIL_P(arr))
- {
- if (TYPE(arr) != T_ARRAY)
- {
- rb_raise(rb_eTypeError, "Kernel#select expects arrays of IO objects");
- }
+ int max_fd = 0;
+ FD_ZERO(set);
+ if (!NIL_P(arr)) {
+ if (TYPE(arr) != T_ARRAY) {
+ rb_raise(rb_eTypeError, "Kernel#select expects arrays of IO objects");
+ }
- long n = RARRAY_LEN(arr);
- long ii;
- for(ii=0; ii<n; ii++)
- {
- VALUE io = RARRAY_AT(arr, ii);
- io = rb_check_convert_type(io, T_FILE, "IO", "to_io");
- if (NIL_P(io))
- {
- rb_raise(rb_eTypeError, "Kernel#select expects arrays of IO objects");
- }
- int fd = ExtractIOStruct(io)->fd;
- FD_SET(fd, set);
- max_fd = MAX(fd, max_fd);
- }
+ long n = RARRAY_LEN(arr);
+ long ii;
+ for (ii = 0; ii < n; ii++) {
+ VALUE io = RARRAY_AT(arr, ii);
+ io = rb_check_convert_type(io, T_FILE, "IO", "to_io");
+ if (NIL_P(io)) {
+ rb_raise(rb_eTypeError, "Kernel#select expects arrays of IO objects");
+ }
+ int fd = ExtractIOStruct(io)->fd;
+ FD_SET(fd, set);
+ max_fd = MAX(fd, max_fd);
}
- return max_fd;
+ }
+ return max_fd;
}
static void
build_timeval_from_numeric(struct timeval *tv, VALUE num)
{
- tv->tv_sec = 0L;
- tv->tv_usec = 0L;
- if(FIXNUM_P(num))
- {
- if (FIX2LONG(num) < 0)
- {
- rb_raise(rb_eArgError, "select() does not accept negative timeouts.");
- }
- tv->tv_sec = FIX2LONG(num);
+ tv->tv_sec = 0L;
+ tv->tv_usec = 0L;
+ if (FIXNUM_P(num)) {
+ if (FIX2LONG(num) < 0) {
+ rb_raise(rb_eArgError, "select() does not accept negative timeouts.");
}
- else if (FIXFLOAT_P(num))
- {
- double quantity = RFLOAT_VALUE(num);
- if (quantity < 0.0)
- {
- rb_raise(rb_eArgError, "select() does not accept negative timeouts.");
- }
- tv->tv_sec = (long)floor(quantity);
- tv->tv_usec = (long)(1000 * (quantity - floor(quantity)));
+ tv->tv_sec = FIX2LONG(num);
+ }
+ else if (FIXFLOAT_P(num)) {
+ double quantity = RFLOAT_VALUE(num);
+ if (quantity < 0.0) {
+ rb_raise(rb_eArgError, "select() does not accept negative timeouts.");
}
- else if (!NIL_P(num))
- {
- rb_raise(rb_eTypeError, "timeout parameter must be numeric.");
- }
+ tv->tv_sec = (long)floor(quantity);
+ tv->tv_usec = (long)(1000 * (quantity - floor(quantity)));
+ }
+ else if (!NIL_P(num)) {
+ rb_raise(rb_eTypeError, "timeout parameter must be numeric.");
+ }
}
static VALUE
extract_ready_descriptors(VALUE arr, fd_set* set)
{
- VALUE ready_ios = rb_ary_new();
- if (NIL_P(arr))
- {
- return ready_ios;
+ VALUE ready_ios = rb_ary_new();
+ if (NIL_P(arr)) {
+ return ready_ios;
+ }
+ long len = RARRAY_LEN(arr);
+ long ii;
+ for (ii = 0; ii < len; ii++) {
+ VALUE io = RARRAY_AT(arr, ii);
+ VALUE tmp = rb_check_convert_type(io, T_FILE, "IO", "to_io");
+ if (FD_ISSET(ExtractIOStruct(tmp)->fd, set)) {
+ rb_ary_push(ready_ios, io);
}
- long len = RARRAY_LEN(arr);
- long ii;
- for (ii=0; ii<len; ii++)
- {
- VALUE io = RARRAY_AT(arr, ii);
- VALUE tmp = rb_check_convert_type(io, T_FILE, "IO", "to_io");
- if (FD_ISSET(ExtractIOStruct(tmp)->fd, set))
- {
- rb_ary_push(ready_ios, io);
- }
- }
- return ready_ios;
+ }
+ return ready_ios;
}
static VALUE
rb_f_select(VALUE recv, SEL sel, int argc, VALUE *argv)
{
- VALUE read_arr, write_arr, err_arr, timeout_val;
- VALUE readable_arr, writable_arr, errored_arr;
- rb_scan_args(argc, argv, "13", &read_arr, &write_arr, &err_arr, &timeout_val);
- fd_set read_set, write_set, err_set;
- struct timeval timeout;
-
- // ndfs has to be 1 + the highest fd we're looking for.
- int temp = 0;
- int ndfs = build_fd_set_from_io_array(&read_set, read_arr);
- temp = build_fd_set_from_io_array(&write_set, write_arr);
- ndfs = MAX(temp, ndfs);
- temp = build_fd_set_from_io_array(&err_set, err_arr);
- ndfs = MAX(temp, ndfs);
- ndfs++;
-
-
- // A timeval of 0 needs to be distinguished from a NULL timeval, as a
- // NULL timeval polls indefinitly while a 0 timeval returns immediately.
- build_timeval_from_numeric(&timeout, timeout_val);
- struct timeval *timeval_ptr = (NIL_P(timeout_val) ? NULL : &timeout);
-
- int ready_count = select(ndfs, &read_set, &write_set, &err_set, timeval_ptr);
- if(ready_count == -1)
- {
- rb_sys_fail("select(2) failed");
- }
- else if (ready_count == 0)
- {
- return Qnil; // no ready file descriptors? return 0.
- }
-
- readable_arr = extract_ready_descriptors(read_arr, &read_set);
- writable_arr = extract_ready_descriptors(write_arr, &write_set);
- errored_arr = extract_ready_descriptors(err_arr, &err_set);
-
- return rb_ary_new3(3, readable_arr, writable_arr, errored_arr);
+ VALUE read_arr, write_arr, err_arr, timeout_val;
+ VALUE readable_arr, writable_arr, errored_arr;
+ rb_scan_args(argc, argv, "13", &read_arr, &write_arr, &err_arr, &timeout_val);
+ fd_set read_set, write_set, err_set;
+ struct timeval timeout;
+
+ // ndfs has to be 1 + the highest fd we're looking for.
+ int temp = 0;
+ int ndfs = build_fd_set_from_io_array(&read_set, read_arr);
+ temp = build_fd_set_from_io_array(&write_set, write_arr);
+ ndfs = MAX(temp, ndfs);
+ temp = build_fd_set_from_io_array(&err_set, err_arr);
+ ndfs = MAX(temp, ndfs);
+ ndfs++;
+
+ // A timeval of 0 needs to be distinguished from a NULL timeval, as a
+ // NULL timeval polls indefinitly while a 0 timeval returns immediately.
+ build_timeval_from_numeric(&timeout, timeout_val);
+ struct timeval *timeval_ptr = (NIL_P(timeout_val) ? NULL : &timeout);
+
+ int ready_count = select(ndfs, &read_set, &write_set, &err_set, timeval_ptr);
+ if (ready_count == -1) {
+ rb_sys_fail("select(2) failed");
+ }
+ else if (ready_count == 0) {
+ return Qnil; // no ready file descriptors? return 0.
+ }
+
+ readable_arr = extract_ready_descriptors(read_arr, &read_set);
+ writable_arr = extract_ready_descriptors(write_arr, &write_set);
+ errored_arr = extract_ready_descriptors(err_arr, &err_set);
+
+ return rb_ary_new3(3, readable_arr, writable_arr, errored_arr);
}
+
// Here be dragons.
static VALUE
rb_io_ctl(VALUE io, VALUE arg, VALUE req, int is_io)
{
- unsigned long request;
+ unsigned long request;
unsigned long cmd = NUM2ULONG(arg);
rb_io_t *io_s = ExtractIOStruct(io);
if (TYPE(req) == T_STRING) {
- request = (unsigned long)(intptr_t)RSTRING_PTR(req);
- } else {
- request = FIX2ULONG(req);
- }
+ request = (unsigned long)(intptr_t)RSTRING_PTR(req);
+ }
+ else {
+ request = FIX2ULONG(req);
+ }
int retval = is_io ? ioctl(io_s->fd, cmd, request) : fcntl(io_s->fd, cmd, request);
return INT2FIX(retval);
}
@@ -3757,9 +3832,8 @@
src_is_path = true;
}
else {
- old_src_offset = rb_io_tell(src, 0); // save the old offset
if (!NIL_P(offset)) {
- // seek if necessary
+ old_src_offset = rb_io_tell(src, 0); // save the old offset
rb_io_seek(src, 0, offset);
}
}
@@ -3806,6 +3880,7 @@
if (!NIL_P(old_src_offset)) {
rb_io_seek(src, old_src_offset, SEEK_SET); // restore the old offset
}
+
return copied;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090723/837a58f4/attachment-0001.html>
More information about the macruby-changes
mailing list