summaryrefslogtreecommitdiff
path: root/file.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-03-07 04:55:34 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-03-07 04:55:34 +0000
commit785b31bed4fbe10dd8fe92a7ef52782d2d1d1123 (patch)
treee72e793ea4c5bc6bbc4e8dfb4d56c32ac45a5b4d /file.c
parent8a144fdedc2df7ee87e21ad805fcbcbd18209533 (diff)
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26841 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'file.c')
-rw-r--r--file.c88
1 files changed, 64 insertions, 24 deletions
diff --git a/file.c b/file.c
index 7aca492c65..50516ad4f8 100644
--- a/file.c
+++ b/file.c
@@ -3166,65 +3166,105 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, char *unresolved, VALUE loopche
}
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 @@ Init_File(void)
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);