[前][次][番号順一覧][スレッド一覧]

ruby-changes:14969

From: akr <ko1@a...>
Date: Sun, 7 Mar 2010 13:55:53 +0900 (JST)
Subject: [ruby-changes:14969] Ruby:r26841 (trunk): * file.c: add optional basedir argument for realpath/realdirpath.

akr	2010-03-07 13:55:34 +0900 (Sun, 07 Mar 2010)

  New Revision: 26841

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=26841

  Log:
    * file.c: add optional basedir argument for realpath/realdirpath.
      (realpath_internal): handle basedir.
      (rb_file_s_realpath): extract basedir from argument list.
      (rb_file_s_realdirpath): extract basedir from argument list.
    
    * lib/pathname.rb (realpath): pass basedir.
      (realdirpath): ditto.

  Modified files:
    trunk/ChangeLog
    trunk/file.c
    trunk/lib/pathname.rb
    trunk/test/pathname/test_pathname.rb
    trunk/test/ruby/test_file.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 26840)
+++ ChangeLog	(revision 26841)
@@ -1,3 +1,13 @@
+Sun Mar  7 13:49:49 2010  Tanaka Akira  <akr@f...>
+
+	* file.c: add optional basedir argument for realpath/realdirpath.
+	  (realpath_internal): handle basedir.
+	  (rb_file_s_realpath): extract basedir from argument list.
+	  (rb_file_s_realdirpath): extract basedir from argument list.
+
+	* lib/pathname.rb (realpath): pass basedir.
+	  (realdirpath): ditto.
+
 Sun Mar  7 02:05:38 2010  NARUSE, Yui  <naruse@r...>
 
 	* encoding.c (enc_set_filesystem_encoding):
Index: lib/pathname.rb
===================================================================
--- lib/pathname.rb	(revision 26840)
+++ lib/pathname.rb	(revision 26841)
@@ -442,8 +442,8 @@
   # All components of the pathname must exist when this method is
   # called.
   #
-  def realpath
-    self.class.new(File.realpath(@path))
+  def realpath(basedir=nil)
+    self.class.new(File.realpath(@path, basedir))
   end
 
   #
@@ -452,8 +452,8 @@
   #
   # The last component of the real pathname can be nonexistent.
   #
-  def realdirpath
-    self.class.new(File.realdirpath(@path))
+  def realdirpath(basedir=nil)
+    self.class.new(File.realdirpath(@path, basedir))
   end
 
   # #parent returns the parent directory.
Index: test/ruby/test_file.rb
===================================================================
--- test/ruby/test_file.rb	(revision 26840)
+++ test/ruby/test_file.rb	(revision 26841)
@@ -157,4 +157,24 @@
     assert_raise(TypeError) { File::Stat.allocate.readable? }
     assert_nothing_raised { File::Stat.allocate.inspect }
   end
+
+  def test_realpath
+    Dir.mktmpdir('rubytest-realpath') {|tmpdir|
+      realdir = File.realpath(tmpdir)
+      tst = realdir.sub(/#{Regexp.escape(File::SEPARATOR)}/, '\0\0\0')
+      assert_equal(realdir, File.realpath(tst))
+      assert_equal(realdir, File.realpath(".", tst))
+    }
+  end
+
+  def test_realdirpath
+    Dir.mktmpdir('rubytest-realdirpath') {|tmpdir|
+      realdir = File.realpath(tmpdir)
+      tst = realdir.sub(/#{Regexp.escape(File::SEPARATOR)}/, '\0\0\0')
+      assert_equal(realdir, File.realdirpath(tst))
+      assert_equal(realdir, File.realdirpath(".", tst))
+      assert_equal(File.join(realdir, "foo"), File.realdirpath("foo", tst))
+    }
+  end
+
 end
Index: test/pathname/test_pathname.rb
===================================================================
--- test/pathname/test_pathname.rb	(revision 26840)
+++ test/pathname/test_pathname.rb	(revision 26841)
@@ -288,8 +288,8 @@
     return true
   end
 
-  def realpath(path)
-    Pathname.new(path).realpath.to_s
+  def realpath(path, basedir=nil)
+    Pathname.new(path).realpath(basedir).to_s
   end
 
   def test_realpath
@@ -301,6 +301,7 @@
 
       File.symlink("loop", "#{dir}/loop")
       assert_raise(Errno::ELOOP) { realpath("#{dir}/loop") }
+      assert_raise(Errno::ELOOP) { realpath("#{dir}/loop", dir) }
 
       File.symlink("../#{File.basename(dir)}/./not-exist-target", "#{dir}/not-exist2")
       assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist2") }
@@ -314,6 +315,7 @@
 
       Dir.mkdir("exist")
       assert_equal("#{dir}/exist", realpath("exist"))
+      assert_raise(Errno::ELOOP) { realpath("../loop", "#{dir}/exist") }
 
       File.symlink("loop1/loop1", "loop1")
       assert_raise(Errno::ELOOP) { realpath("#{dir}/loop1") }
Index: file.c
===================================================================
--- file.c	(revision 26840)
+++ file.c	(revision 26841)
@@ -3166,65 +3166,105 @@
 }
 
 static VALUE
-realpath_internal(VALUE path, int strict)
+realpath_internal(VALUE basedir, VALUE path, int strict)
 {
     long prefixlen;
     VALUE resolved;
     volatile VALUE unresolved_path;
-    char *unresolved_names;
     VALUE loopcheck;
+    volatile VALUE curdir = Qnil;
+    
+    char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL;
+    char *ptr;
 
     rb_secure(2);
 
     FilePathValue(path);
     unresolved_path = rb_str_dup_frozen(path);
-    unresolved_names = skiproot(RSTRING_PTR(unresolved_path));
-    prefixlen = unresolved_names - RSTRING_PTR(unresolved_path);
-    loopcheck = rb_hash_new();
-    if (prefixlen == 0) {
-        volatile VALUE curdir = rb_dir_getwd();
-        char *unresolved_curdir_names = skiproot(RSTRING_PTR(curdir));
-        prefixlen = unresolved_curdir_names - RSTRING_PTR(curdir);
-        resolved = rb_str_new(RSTRING_PTR(curdir), prefixlen);
-        realpath_rec(&prefixlen, &resolved, unresolved_curdir_names, loopcheck, 1, 0);
+
+    if (!NIL_P(basedir)) {
+        FilePathValue(basedir);
+        basedir = rb_str_dup_frozen(basedir);
     }
-    else {
-        resolved = rb_str_new(RSTRING_PTR(unresolved_path), prefixlen);
+
+    ptr = RSTRING_PTR(unresolved_path);
+    path_names = skiproot(ptr);
+    if (ptr != path_names) {
+        resolved = rb_str_new(ptr, path_names - ptr);
+        goto root_found;
     }
-    realpath_rec(&prefixlen, &resolved, unresolved_names, loopcheck, strict, 1);
+
+    if (!NIL_P(basedir)) {
+        ptr = RSTRING_PTR(basedir);
+        basedir_names = skiproot(ptr);
+        if (ptr != basedir_names) {
+            resolved = rb_str_new(ptr, basedir_names - ptr);
+            goto root_found;
+        }
+    }
+
+    curdir = rb_dir_getwd();
+    ptr = RSTRING_PTR(curdir);
+    curdir_names = skiproot(ptr);
+    resolved = rb_str_new(ptr, curdir_names - ptr);
+
+  root_found:
+    ptr = chompdirsep(RSTRING_PTR(resolved));
+    if (*ptr) {
+        rb_str_set_len(resolved, ptr - RSTRING_PTR(resolved) + 1);
+    }
+    prefixlen = RSTRING_LEN(resolved);
+
+    loopcheck = rb_hash_new();
+    if (curdir_names)
+        realpath_rec(&prefixlen, &resolved, curdir_names, loopcheck, 1, 0);
+    if (basedir_names)
+        realpath_rec(&prefixlen, &resolved, basedir_names, loopcheck, 1, 0);
+    realpath_rec(&prefixlen, &resolved, path_names, loopcheck, strict, 1);
+
     OBJ_TAINT(resolved);
     return resolved;
 }
 
 /*
  * call-seq:
- *     File.realpath(pathname) -> real_pathname
+ *     File.realpath(pathname [, dir_string]) -> real_pathname
  *
- *  Returns the real (absolute) pathname of +pathname+ in the actual
+ *  Returns the real (absolute) pathname of _pathname_ in the actual
  *  filesystem not containing symlinks or useless dots.
+ *
+ *  If _dir_string_ is given, it is used as a base directory
+ *  for interpreting relative pathname instead of the current directory.
  * 
  *  All components of the pathname must exist when this method is
  *  called.
  */
 static VALUE
-rb_file_s_realpath(VALUE klass, VALUE path)
+rb_file_s_realpath(int argc, VALUE *argv, VALUE klass)
 {
-    return realpath_internal(path, 1);
+    VALUE path, basedir;
+    rb_scan_args(argc, argv, "11", &path, &basedir);
+    return realpath_internal(basedir, path, 1);
 }
 
 /*
  * call-seq:
- *     File.realdirpath(pathname) -> real_pathname
+ *     File.realdirpath(pathname [, dir_string]) -> real_pathname
  *
- *  Returns the real (absolute) pathname of +pathname+ in the actual filesystem.
+ *  Returns the real (absolute) pathname of _pathname_ in the actual filesystem.
  *  The real pathname doesn't contain symlinks or useless dots.
  * 
+ *  If _dir_string_ is given, it is used as a base directory
+ *  for interpreting relative pathname instead of the current directory.
+ * 
  *  The last component of the real pathname can be nonexistent.
  */
 static VALUE
-rb_file_s_realdirpath(VALUE klass, VALUE path)
+rb_file_s_realdirpath(int argc, VALUE *argv, VALUE klass)
 {
-    return realpath_internal(path, 0);
+    VALUE path, basedir;
+    rb_scan_args(argc, argv, "11", &path, &basedir);
+    return realpath_internal(basedir, path, 0);
 }
 
 static size_t
@@ -5041,8 +5081,8 @@
     rb_define_singleton_method(rb_cFile, "truncate", rb_file_s_truncate, 2);
     rb_define_singleton_method(rb_cFile, "expand_path", rb_file_s_expand_path, -1);
     rb_define_singleton_method(rb_cFile, "absolute_path", rb_file_s_absolute_path, -1);
-    rb_define_singleton_method(rb_cFile, "realpath", rb_file_s_realpath, 1);
-    rb_define_singleton_method(rb_cFile, "realdirpath", rb_file_s_realdirpath, 1);
+    rb_define_singleton_method(rb_cFile, "realpath", rb_file_s_realpath, -1);
+    rb_define_singleton_method(rb_cFile, "realdirpath", rb_file_s_realdirpath, -1);
     rb_define_singleton_method(rb_cFile, "basename", rb_file_s_basename, -1);
     rb_define_singleton_method(rb_cFile, "dirname", rb_file_s_dirname, 1);
     rb_define_singleton_method(rb_cFile, "extname", rb_file_s_extname, 1);

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]