about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-05-13 17:48:56 -0700
committerEric Wong <normalperson@yhbt.net>2011-05-13 17:48:56 -0700
commitc8bd876fb5086e5b79299869b4c29f1f7f020b4d (patch)
tree10b61224b90047b9c1c9b0252aacba32505e3ec2
parent6cefcff5889cceaa001f76f4be1a1c5e513b241d (diff)
downloadkgio-c8bd876fb5086e5b79299869b4c29f1f7f020b4d.tar.gz
This also allows us to return/override #to_path and #path if
necessary, but so far everything works with MRI 1.8, MRI 1.9,
and Rubinius.
-rw-r--r--ext/kgio/extconf.rb2
-rw-r--r--ext/kgio/set_file_path.h26
-rw-r--r--ext/kgio/tryopen.c29
-rw-r--r--test/test_tryopen.rb4
4 files changed, 54 insertions, 7 deletions
diff --git a/ext/kgio/extconf.rb b/ext/kgio/extconf.rb
index f44b8c8..f988ce1 100644
--- a/ext/kgio/extconf.rb
+++ b/ext/kgio/extconf.rb
@@ -19,12 +19,14 @@ if have_header('ruby/io.h')
   rubyio = %w(ruby.h ruby/io.h)
   have_struct_member("rb_io_t", "fd", rubyio)
   have_struct_member("rb_io_t", "mode", rubyio)
+  have_struct_member("rb_io_t", "pathv", rubyio)
 else
   rubyio = %w(ruby.h rubyio.h)
   rb_io_t = have_type("OpenFile", rubyio) ? "OpenFile" : "rb_io_t"
   have_struct_member(rb_io_t, "f", rubyio)
   have_struct_member(rb_io_t, "f2", rubyio)
   have_struct_member(rb_io_t, "mode", rubyio)
+  have_struct_member(rb_io_t, "path", rubyio)
   have_func('rb_fdopen')
 end
 have_type("struct RFile", rubyio) and check_sizeof("struct RFile", rubyio)
diff --git a/ext/kgio/set_file_path.h b/ext/kgio/set_file_path.h
new file mode 100644
index 0000000..50fd338
--- /dev/null
+++ b/ext/kgio/set_file_path.h
@@ -0,0 +1,26 @@
+#if defined(HAVE_RB_IO_T) && \
+    defined(HAVE_TYPE_STRUCT_RFILE) && \
+    defined(HAVE_ST_PATHV)
+/* MRI 1.9 */
+static void set_file_path(VALUE io, VALUE path)
+{
+        rb_io_t *fptr = RFILE(io)->fptr;
+        fptr->pathv = rb_str_new4(path);
+}
+#elif defined(HAVE_TYPE_OPENFILE) && \
+      defined(HAVE_TYPE_STRUCT_RFILE) && \
+      defined(HAVE_ST_PATH)
+/* MRI 1.8 */
+#include "util.h"
+static void set_file_path(VALUE io, VALUE path)
+{
+        OpenFile *fptr = RFILE(io)->fptr;
+        fptr->path = ruby_strdup(RSTRING_PTR(path));
+}
+#else
+/* Rubinius */
+static void set_file_path(VALUE io, VALUE path)
+{
+        rb_iv_set(io, "@path", rb_str_new4(path));
+}
+#endif
diff --git a/ext/kgio/tryopen.c b/ext/kgio/tryopen.c
index c9d7bb6..6ba9618 100644
--- a/ext/kgio/tryopen.c
+++ b/ext/kgio/tryopen.c
@@ -14,9 +14,11 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include "set_file_path.h"
 
-static ID id_for_fd, id_to_path;
+static ID id_for_fd, id_to_path, id_path;
 static st_table *errno2sym;
+static VALUE cFile;
 
 struct open_args {
         const char *pathname;
@@ -32,13 +34,16 @@ static VALUE nogvl_open(void *ptr)
 }
 
 #ifndef HAVE_RB_THREAD_BLOCKING_REGION
-#  define RUBY_UBF_IO (-1)
+#  define RUBY_UBF_IO ((void *)(-1))
+#  include "rubysig.h"
 typedef void rb_unblock_function_t(void *);
 typedef VALUE rb_blocking_function_t(void *);
 static VALUE rb_thread_blocking_region(
         rb_blocking_function_t *fn, void *data1,
         rb_unblock_function_t *ubf, void *data2)
 {
+        VALUE rv;
+
         TRAP_BEG; /* for FIFO */
         rv = fn(data1);
         TRAP_END;
@@ -53,8 +58,11 @@ static VALUE s_tryopen(int argc, VALUE *argv, VALUE klass)
         VALUE pathname, flags, mode;
         struct open_args o;
         int retried = 0;
+        VALUE rv;
 
         rb_scan_args(argc, argv, "12", &pathname, &flags, &mode);
+        if (rb_respond_to(pathname, id_to_path))
+                pathname = rb_funcall(pathname, id_to_path, 0);
         o.pathname = StringValueCStr(pathname);
 
         switch (TYPE(flags)) {
@@ -82,7 +90,6 @@ retry:
                 }
                 if (fd == -1) {
                         int saved_errno = errno;
-                        VALUE rv;
 
                         if (!st_lookup(errno2sym, (st_data_t)errno, &rv)) {
                                 errno = saved_errno;
@@ -91,7 +98,9 @@ retry:
                         return rv;
                 }
         }
-        return rb_funcall(rb_cFile, id_for_fd, 1, INT2FIX(fd));
+        rv = rb_funcall(cFile, id_for_fd, 1, INT2FIX(fd));
+        set_file_path(rv, pathname);
+        return rv;
 }
 
 void init_kgio_tryopen(void)
@@ -101,10 +110,17 @@ void init_kgio_tryopen(void)
         VALUE *ptr;
         long len;
 
-        rb_define_singleton_method(mKgio, "tryopen", s_tryopen, -1);
+        id_path = rb_intern("path");
         id_for_fd = rb_intern("for_fd");
         id_to_path = rb_intern("to_path");
 
+        rb_define_singleton_method(mKgio, "tryopen", s_tryopen, -1);
+        cFile = rb_define_class_under(mKgio, "File", rb_cFile);
+
+        if (!rb_funcall(cFile, rb_intern("method_defined?"), 1,
+                        ID2SYM(id_to_path)))
+                rb_define_alias(cFile, "to_path", "path");
+
         errno2sym = st_init_numtable();
         tmp = rb_funcall(rb_mErrno, rb_intern("constants"), 0);
         ptr = RARRAY_PTR(tmp);
@@ -120,7 +136,8 @@ void init_kgio_tryopen(void)
                 }
 
                 error = rb_const_get(rb_mErrno, const_id);
-                if (!rb_const_defined(error, rb_intern("Errno")))
+                if ((TYPE(error) != T_CLASS) ||
+                    !rb_const_defined(error, rb_intern("Errno")))
                         continue;
 
                 error = rb_const_get(error, rb_intern("Errno"));
diff --git a/test/test_tryopen.rb b/test/test_tryopen.rb
index c885ca0..ca80460 100644
--- a/test/test_tryopen.rb
+++ b/test/test_tryopen.rb
@@ -7,8 +7,10 @@ class TestTryopen < Test::Unit::TestCase
 
   def test_tryopen_success
     tmp = Kgio.tryopen(__FILE__)
-    assert_instance_of File, tmp
+    assert_kind_of File, tmp
     assert_equal File.read(__FILE__), tmp.read
+    assert_equal __FILE__, tmp.path
+    assert_equal __FILE__, tmp.to_path
     assert_nothing_raised { tmp.close }
   end