summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--dir.c25
-rw-r--r--file.c86
3 files changed, 78 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog
index 2d85f349b9..abeee08369 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Mon Feb 2 16:33:06 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (dir_s_home): new method. [ruby-core:21454]
+
Mon Feb 2 16:06:10 2009 Tanaka Akira <akr@fsij.org>
* version.h: bump up to 1.9.2 patchlevel -1.
diff --git a/dir.c b/dir.c
index f5e8cf72e8..f938fae721 100644
--- a/dir.c
+++ b/dir.c
@@ -1852,6 +1852,30 @@ file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
return Qfalse;
}
+VALUE rb_home_dir(const char *user, VALUE result);
+
+/*
+ * call-seq:
+ * Dir.home() => "/home/me"
+ * Dir.home("root") => "/root"
+ *
+ * Returns the home directory of the current user or the named user
+ * if given.
+ */
+static VALUE
+dir_s_home(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE user;
+ const char *u = 0;
+
+ rb_scan_args(argc, argv, "01", &user);
+ if (!NIL_P(user)) {
+ SafeStringValue(user);
+ u = StringValueCStr(user);
+ }
+ return rb_home_dir(u, rb_str_new(0, 0));
+}
+
/*
* Objects of class <code>Dir</code> are directory streams representing
* directories in the underlying file system. They provide a variety of
@@ -1895,6 +1919,7 @@ Init_Dir(void)
rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1);
rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1);
rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
+ rb_define_singleton_method(rb_cDir,"home", dir_s_home, -1);
rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
diff --git a/file.c b/file.c
index 8debc150ee..b035a0b064 100644
--- a/file.c
+++ b/file.c
@@ -2600,6 +2600,46 @@ ntfs_tail(const char *path)
static int is_absolute_path(const char*);
+VALUE
+rb_home_dir(const char *user, VALUE result)
+{
+ const char *dir;
+ char *buf;
+ long dirlen;
+
+ if (!user || !*user) {
+ if (!(dir = getenv("HOME"))) {
+ rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
+ }
+ dirlen = strlen(dir);
+ rb_str_resize(result, dirlen);
+ memcpy(buf = RSTRING_PTR(result), dir, dirlen);
+ }
+ else {
+#ifdef HAVE_GETPWENT
+ struct passwd *pwPtr = getpwnam(user);
+ if (!pwPtr) {
+ endpwent();
+ rb_raise(rb_eArgError, "user %s doesn't exist", user);
+ }
+ dirlen = strlen(pwPtr->pw_dir);
+ rb_str_resize(result, dirlen);
+ strcpy(buf = RSTRING_PTR(result), pwPtr->pw_dir);
+ endpwent();
+#else
+ return Qnil;
+#endif
+ }
+#if defined DOSISH || defined __CYGWIN__
+ for (p = buf; *p; p = CharNext(p)) {
+ if (*p == '\\') {
+ *p = '/';
+ }
+ }
+#endif
+ return result;
+}
+
static VALUE
file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result)
{
@@ -2615,51 +2655,23 @@ file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result)
tainted = OBJ_TAINTED(fname);
if (s[0] == '~' && abs_mode == 0) { /* execute only if NOT absolute_path() */
+ tainted = 1;
if (isdirsep(s[1]) || s[1] == '\0') {
- const char *dir = getenv("HOME");
-
- if (!dir) {
- rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `%s'", s);
- }
- dirlen = strlen(dir);
- BUFCHECK(dirlen > buflen);
- strcpy(buf, dir);
-#if defined DOSISH || defined __CYGWIN__
- for (p = buf; *p; p = CharNext(p)) {
- if (*p == '\\') {
- *p = '/';
- }
- }
-#else
- p = buf + strlen(dir);
-#endif
- s++;
- tainted = 1;
- SET_EXTERNAL_ENCODING();
+ buf = 0;
+ rb_str_set_len(result, 0);
+ if (*++s) ++s;
}
else {
-#ifdef HAVE_PWD_H
- struct passwd *pwPtr;
- s++;
-#endif
s = nextdirsep(b = s);
BUFCHECK(bdiff + (s-b) >= buflen);
memcpy(p, b, s-b);
+ rb_str_set_len(result, s-b);
+ buf = p + 1;
p += s-b;
- *p = '\0';
-#ifdef HAVE_PWD_H
- pwPtr = getpwnam(buf);
- if (!pwPtr) {
- endpwent();
- rb_raise(rb_eArgError, "user %s doesn't exist", buf);
- }
- dirlen = strlen(pwPtr->pw_dir);
- BUFCHECK(dirlen > buflen);
- strcpy(buf, pwPtr->pw_dir);
- p = buf + strlen(pwPtr->pw_dir);
- endpwent();
-#endif
}
+ rb_home_dir(buf, result);
+ BUFINIT();
+ p = pend;
}
#ifdef DOSISH_DRIVE_LETTER
/* skip drive letter */