зеркало из https://github.com/github/ruby.git
dir.c: Dir.empty?
* dir.c (rb_dir_s_empty_p): add Dir.empty? method, which tells the argument is the name of an empty directory. [Feature #10121] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53841 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
9cedfbcb91
Коммит
135a171ce1
|
@ -1,3 +1,8 @@
|
||||||
|
Tue Feb 16 17:34:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* dir.c (rb_dir_s_empty_p): add Dir.empty? method, which tells the
|
||||||
|
argument is the name of an empty directory. [Feature #10121]
|
||||||
|
|
||||||
Tue Feb 16 09:51:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Tue Feb 16 09:51:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* tool/rbinstall.rb (without_destdir): just strip a drive letter
|
* tool/rbinstall.rb (without_destdir): just strip a drive letter
|
||||||
|
|
4
NEWS
4
NEWS
|
@ -16,6 +16,10 @@ with all sufficient information, see the ChangeLog file or Redmine
|
||||||
|
|
||||||
=== Core classes updates (outstanding ones only)
|
=== Core classes updates (outstanding ones only)
|
||||||
|
|
||||||
|
* Dir
|
||||||
|
|
||||||
|
* Dir#empty?. [Feature #10121]
|
||||||
|
|
||||||
=== Stdlib updates (outstanding ones only)
|
=== Stdlib updates (outstanding ones only)
|
||||||
|
|
||||||
* CSV
|
* CSV
|
||||||
|
|
91
dir.c
91
dir.c
|
@ -21,6 +21,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#undef HAVE_DIRENT_NAMLEN
|
||||||
#if defined HAVE_DIRENT_H && !defined _WIN32
|
#if defined HAVE_DIRENT_H && !defined _WIN32
|
||||||
# include <dirent.h>
|
# include <dirent.h>
|
||||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
#else
|
#else
|
||||||
# define dirent direct
|
# define dirent direct
|
||||||
# define NAMLEN(dirent) (dirent)->d_namlen
|
# define NAMLEN(dirent) (dirent)->d_namlen
|
||||||
|
# define HAVE_DIRENT_NAMLEN 1
|
||||||
# if HAVE_SYS_NDIR_H
|
# if HAVE_SYS_NDIR_H
|
||||||
# include <sys/ndir.h>
|
# include <sys/ndir.h>
|
||||||
# endif
|
# endif
|
||||||
|
@ -699,6 +701,27 @@ fundamental_encoding_p(rb_encoding *enc)
|
||||||
#else
|
#else
|
||||||
# define READDIR(dir, enc) readdir((dir))
|
# define READDIR(dir, enc) readdir((dir))
|
||||||
#endif
|
#endif
|
||||||
|
static int
|
||||||
|
to_be_skipped(const struct dirent *dp)
|
||||||
|
{
|
||||||
|
const char *name = dp->d_name;
|
||||||
|
if (name[0] != '.') return FALSE;
|
||||||
|
#ifdef HAVE_DIRENT_NAMLEN
|
||||||
|
switch (NAMLEN(dp)) {
|
||||||
|
case 2:
|
||||||
|
if (name[1] != '.') return FALSE;
|
||||||
|
case 1:
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!name[1]) return TRUE;
|
||||||
|
if (name[1] != '.') return FALSE;
|
||||||
|
if (!name[2]) return TRUE;
|
||||||
|
#endif
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
|
@ -2610,6 +2633,73 @@ rb_dir_exists_p(VALUE obj, VALUE fname)
|
||||||
return rb_file_directory_p(obj, fname);
|
return rb_file_directory_p(obj, fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Dir.empty?(path_name) -> true or false
|
||||||
|
*
|
||||||
|
* Returns <code>true</code> if the named file is an empty directory,
|
||||||
|
* <code>false</code> if it is not a directory or non-empty.
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
rb_dir_s_empty_p(VALUE obj, VALUE dirname)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *dp;
|
||||||
|
VALUE result = Qtrue, orig;
|
||||||
|
const char *path;
|
||||||
|
enum {false_on_notdir = 1};
|
||||||
|
|
||||||
|
GlobPathValue(dirname, FALSE);
|
||||||
|
orig = rb_str_dup_frozen(dirname);
|
||||||
|
dirname = rb_str_encode_ospath(dirname);
|
||||||
|
dirname = rb_str_dup_frozen(dirname);
|
||||||
|
path = RSTRING_PTR(dirname);
|
||||||
|
|
||||||
|
#if defined HAVE_GETATTRLIST && defined ATTR_DIR_ENTRYCOUNT
|
||||||
|
{
|
||||||
|
u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
|
||||||
|
struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
|
||||||
|
if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) != 0)
|
||||||
|
rb_sys_fail_path(orig);
|
||||||
|
if (*(const fsobj_tag_t *)(attrbuf+1) == VT_HFS) {
|
||||||
|
al.commonattr = 0;
|
||||||
|
al.dirattr = ATTR_DIR_ENTRYCOUNT;
|
||||||
|
if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) == 0) {
|
||||||
|
if (attrbuf[0] >= 2 * sizeof(u_int32_t))
|
||||||
|
return attrbuf[1] ? Qfalse : Qtrue;
|
||||||
|
if (false_on_notdir) return Qfalse;
|
||||||
|
}
|
||||||
|
rb_sys_fail_path(orig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
|
if (!dir) {
|
||||||
|
int e = errno;
|
||||||
|
switch (e) {
|
||||||
|
case EMFILE: case ENFILE:
|
||||||
|
rb_gc();
|
||||||
|
dir = opendir(path);
|
||||||
|
if (dir) break;
|
||||||
|
e = errno;
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
if (false_on_notdir && e == ENOTDIR) return Qfalse;
|
||||||
|
rb_syserr_fail_path(e, orig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errno = 0;
|
||||||
|
while ((dp = READDIR(dir, NULL)) != NULL) {
|
||||||
|
if (!to_be_skipped(dp)) {
|
||||||
|
result = Qfalse;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Objects of class <code>Dir</code> are directory streams representing
|
* Objects of class <code>Dir</code> are directory streams representing
|
||||||
* directories in the underlying file system. They provide a variety of
|
* directories in the underlying file system. They provide a variety of
|
||||||
|
@ -2661,6 +2751,7 @@ Init_Dir(void)
|
||||||
rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
|
rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
|
||||||
rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1);
|
rb_define_singleton_method(rb_cDir,"exist?", rb_file_directory_p, 1);
|
||||||
rb_define_singleton_method(rb_cDir,"exists?", rb_dir_exists_p, 1);
|
rb_define_singleton_method(rb_cDir,"exists?", rb_dir_exists_p, 1);
|
||||||
|
rb_define_singleton_method(rb_cDir,"empty?", rb_dir_s_empty_p, 1);
|
||||||
|
|
||||||
rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
|
rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
|
||||||
rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
|
rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
|
||||||
|
|
|
@ -331,4 +331,13 @@ class TestDir < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_empty?
|
||||||
|
assert_not_send([Dir, :empty?, @root])
|
||||||
|
assert_send([Dir, :empty?, File.join(@root, "a")])
|
||||||
|
open(File.join(@root, "a", "..."), "w") {}
|
||||||
|
assert_not_send([Dir, :empty?, File.join(@root, "a")])
|
||||||
|
assert_raise(Errno::ENOENT) {Dir.empty?(@nodir)}
|
||||||
|
assert_not_send([Dir, :empty?, File.join(@root, "b")])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Загрузка…
Ссылка в новой задаче