From ca525d5482e65799cbeb31ef0d8b3bccc6e2b49e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 24 Dec 2012 20:11:55 -0800 Subject: [PATCH 01/40] Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..9d43b76a7 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +mruby-dir +========= \ No newline at end of file From 7a593bf2d43a7430f86c296dca0d65f6b283129e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 25 Dec 2012 13:32:29 +0900 Subject: [PATCH 02/40] Dir class for mruby (from iij/mruby) --- .gitignore | 5 ++ mrblib/dir.rb | 49 +++++++++++ src/dir.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/dir.rb | 0 4 files changed, 282 insertions(+) create mode 100644 .gitignore create mode 100644 mrblib/dir.rb create mode 100644 src/dir.c create mode 100644 test/dir.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3ffde7df0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +Makefile +gem_* +gem-* +mrb-*.a +src/*.o diff --git a/mrblib/dir.rb b/mrblib/dir.rb new file mode 100644 index 000000000..b53a7102a --- /dev/null +++ b/mrblib/dir.rb @@ -0,0 +1,49 @@ +class Dir + def each(&block) + while s = self.read + block.call(s) + end + self + end + + alias pos tell + alias pos= seek + + def self.entries(path) + a = [] + self.open(path) { |d| + while s = d.read + a << s + end + } + a + end + + def self.foreach(path, &block) + if block + self.open(path).each { |f| block.call(f) } + else + self.open(path).each + end + end + + def self.open(path, &block) + if block + d = self.new(path) + begin + block.call(d) + ensure + d.close + end + else + self.new(path) + end + end + + class << self + alias exists? exist? + alias pwd getwd + alias rmdir delete + alias unlink delete + end +end diff --git a/src/dir.c b/src/dir.c new file mode 100644 index 000000000..e061817fa --- /dev/null +++ b/src/dir.c @@ -0,0 +1,228 @@ +/* +** dir.c - Dir +** +** See Copyright Notice in mruby.h +*/ + +#include "mruby.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* with/without IO module */ +#ifdef ENABLE_IO +#include "mruby/ext/io.h" +#else +#define E_IO_ERROR E_RUNTIME_ERROR +#endif + +struct mrb_dir { + DIR *dir; +}; + +void +mrb_dir_free(mrb_state *mrb, void *ptr) +{ + struct mrb_dir *mdir = ptr; + + if (mdir->dir) { + closedir(mdir->dir); + mdir->dir = NULL; + } + mrb_free(mrb, mdir); +} + +static struct mrb_data_type mrb_dir_type = { "DIR", mrb_dir_free }; + +mrb_value +mrb_dir_close(mrb_state *mrb, mrb_value self) +{ + struct mrb_dir *mdir; + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + if (closedir(mdir->dir) == -1) { + mrb_sys_fail(mrb, "closedir"); + } + mdir->dir = NULL; + return mrb_nil_value(); +} + +mrb_value +mrb_dir_init(mrb_state *mrb, mrb_value self) +{ + DIR *dir; + struct mrb_dir *mdir; + mrb_value path; + char *cpath; + + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (mdir) { + mrb_dir_free(mrb, mdir); + } + + mdir = (struct mrb_dir *)mrb_malloc(mrb, sizeof(*mdir)); + mdir->dir = NULL; + DATA_PTR(self) = mdir; + DATA_TYPE(self) = &mrb_dir_type; + + mrb_get_args(mrb, "S", &path); + cpath = mrb_str_to_cstr(mrb, path); + if ((dir = opendir(cpath)) == NULL) { + mrb_sys_fail(mrb, cpath); + } + mdir->dir = dir; + return self; +} + +mrb_value +mrb_dir_delete(mrb_state *mrb, mrb_value klass) +{ + mrb_value path; + char *cpath; + + mrb_get_args(mrb, "S", &path); + cpath = mrb_str_to_cstr(mrb, path); + if (rmdir(cpath) == -1) { + mrb_sys_fail(mrb, cpath); + } + return mrb_fixnum_value(0); +} + +mrb_value +mrb_dir_existp(mrb_state *mrb, mrb_value klass) +{ + mrb_value path; + struct stat sb; + char *cpath; + + mrb_get_args(mrb, "S", &path); + cpath = mrb_str_to_cstr(mrb, path); + if (stat(cpath, &sb) == 0 && S_ISDIR(sb.st_mode)) { + return mrb_true_value(); + } else { + return mrb_false_value(); + } +} + +mrb_value +mrb_dir_getwd(mrb_state *mrb, mrb_value klass) +{ + mrb_value path; + + path = mrb_str_buf_new(mrb, MAXPATHLEN); + if (getcwd(RSTRING_PTR(path), MAXPATHLEN) == NULL) { + mrb_sys_fail(mrb, "getcwd(2)"); + } + mrb_str_resize(mrb, path, strlen(RSTRING_PTR(path))); + return path; +} + +mrb_value +mrb_dir_mkdir(mrb_state *mrb, mrb_value klass) +{ + mrb_int mode; + mrb_value spath; + char *path; + + mode = 0777; + mrb_get_args(mrb, "S|i", &spath, &mode); + path = mrb_str_to_cstr(mrb, spath); + if (mkdir(path, mode) == -1) { + mrb_sys_fail(mrb, path); + } + return mrb_fixnum_value(0); +} + +mrb_value +mrb_dir_read(mrb_state *mrb, mrb_value self) +{ + struct mrb_dir *mdir; + struct dirent *dp; + + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + dp = readdir(mdir->dir); + if (dp != NULL) { + return mrb_str_new2(mrb, dp->d_name); + } else { + return mrb_nil_value(); + } +} + +mrb_value +mrb_dir_rewind(mrb_state *mrb, mrb_value self) +{ + struct mrb_dir *mdir; + + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + rewinddir(mdir->dir); + return self; +} + +mrb_value +mrb_dir_seek(mrb_state *mrb, mrb_value self) +{ + struct mrb_dir *mdir; + mrb_int pos; + + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + mrb_get_args(mrb, "i", &pos); + seekdir(mdir->dir, (long)pos); + return self; +} + +mrb_value +mrb_dir_tell(mrb_state *mrb, mrb_value self) +{ + struct mrb_dir *mdir; + mrb_int pos; + + mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + if (!mdir) return mrb_nil_value(); + if (!mdir->dir) { + mrb_raise(mrb, E_IO_ERROR, "closed directory"); + } + pos = (mrb_int)telldir(mdir->dir); + return mrb_fixnum_value(pos); +} + +void +mrb_mruby_dir_gem_init(mrb_state *mrb) +{ + struct RClass *d; + + d = mrb_define_class(mrb, "Dir", mrb->object_class); + MRB_SET_INSTANCE_TT(d, MRB_TT_DATA); + mrb_define_class_method(mrb, d, "delete", mrb_dir_delete, ARGS_REQ(1)); + mrb_define_class_method(mrb, d, "exist?", mrb_dir_existp, ARGS_REQ(1)); + mrb_define_class_method(mrb, d, "getwd", mrb_dir_getwd, ARGS_NONE()); + mrb_define_class_method(mrb, d, "mkdir", mrb_dir_mkdir, ARGS_REQ(1)|ARGS_OPT(1)); + mrb_define_method(mrb, d, "close", mrb_dir_close, ARGS_NONE()); + mrb_define_method(mrb, d, "initialize", mrb_dir_init, ARGS_REQ(1)); + mrb_define_method(mrb, d, "read", mrb_dir_read, ARGS_NONE()); + mrb_define_method(mrb, d, "rewind", mrb_dir_rewind, ARGS_NONE()); + mrb_define_method(mrb, d, "seek", mrb_dir_seek, ARGS_REQ(1)); + mrb_define_method(mrb, d, "tell", mrb_dir_tell, ARGS_NONE()); +} diff --git a/test/dir.rb b/test/dir.rb new file mode 100644 index 000000000..e69de29bb From f210dd553e3ade5820c59560551dab3c772934b8 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 25 Dec 2012 13:34:52 +0900 Subject: [PATCH 03/40] requires iij/mruby. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d43b76a7..0a148700e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ mruby-dir -========= \ No newline at end of file +========= + +Note: mruby-dir requires iij/mruby now. From 92ad6dc8c3ba79324401d99dd066e4962e5eeaaf Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 25 Dec 2012 13:44:22 +0900 Subject: [PATCH 04/40] should not ignore Makefile... --- .gitignore | 1 - Makefile | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 Makefile diff --git a/.gitignore b/.gitignore index 3ffde7df0..f28a84016 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -Makefile gem_* gem-* mrb-*.a diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..80868955b --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +GEM := mruby-dir + +include $(MAKEFILE_4_GEM) + +GEM_C_FILES := $(wildcard $(SRC_DIR)/*.c) +GEM_OBJECTS := $(patsubst %.c, %.o, $(GEM_C_FILES)) + +GEM_RB_FILES := $(wildcard $(MRB_DIR)/*.rb) + +gem-all : $(GEM_OBJECTS) gem-c-and-rb-files + +gem-clean : gem-clean-c-and-rb-files + +gem-test : gem-test-c-and-rb-files From 2e2225e2d312177537b4e471c5c3caa712dadde4 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Jan 2013 00:19:04 +0900 Subject: [PATCH 05/40] add mrbgem.rake --- mrbgem.rake | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 mrbgem.rake diff --git a/mrbgem.rake b/mrbgem.rake new file mode 100644 index 000000000..52a8baa95 --- /dev/null +++ b/mrbgem.rake @@ -0,0 +1,17 @@ +MRuby::Gem::Specification.new('mruby-dir') do |spec| + spec.license = 'MIT' + spec.authors = 'mruby developers' + + # spec.cflags = '' + + # spec.mruby_cflags = '' + # spec.mruby_ldflags = '' + # spec.mruby_libs = '' + spec.mruby_includes = ["#{build.root}/src"] + + # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") + # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") + # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.test_preload = 'test/assert.rb' +end From 2f486fbccb85e48b934683703b70255323d82d05 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 24 Jan 2013 10:18:05 +0900 Subject: [PATCH 06/40] add mrb_mruby_dir_gem_final --- src/dir.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/dir.c b/src/dir.c index e061817fa..9aab0b1cb 100644 --- a/src/dir.c +++ b/src/dir.c @@ -226,3 +226,8 @@ mrb_mruby_dir_gem_init(mrb_state *mrb) mrb_define_method(mrb, d, "seek", mrb_dir_seek, ARGS_REQ(1)); mrb_define_method(mrb, d, "tell", mrb_dir_tell, ARGS_NONE()); } + +void +mrb_mruby_dir_gem_final(mrb_state *mrb) +{ +} From 6b7e81f75b88d707a06a761694c439e280475d75 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 24 Jan 2013 10:18:13 +0900 Subject: [PATCH 07/40] update mrbgem.rake --- mrbgem.rake | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/mrbgem.rake b/mrbgem.rake index 52a8baa95..607a87e64 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -1,17 +1,6 @@ MRuby::Gem::Specification.new('mruby-dir') do |spec| spec.license = 'MIT' spec.authors = 'mruby developers' - - # spec.cflags = '' - - # spec.mruby_cflags = '' - # spec.mruby_ldflags = '' - # spec.mruby_libs = '' - spec.mruby_includes = ["#{build.root}/src"] - - # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") - # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } - # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") - # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } - # spec.test_preload = 'test/assert.rb' + + spec.cc.include_paths << "#{build.root}/src" end From ae5671369e055c7ee42997f236feb7d68e41293d Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 30 Jan 2013 15:11:15 +0900 Subject: [PATCH 08/40] update mrbgem.rake --- mrbgem.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgem.rake b/mrbgem.rake index 607a87e64..670298049 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -1,6 +1,6 @@ MRuby::Gem::Specification.new('mruby-dir') do |spec| spec.license = 'MIT' - spec.authors = 'mruby developers' + spec.authors = 'Internet Initiative Japan Inc.' spec.cc.include_paths << "#{build.root}/src" end From 04d51d9719af7807f0f46d448b12350fa4c2a6cc Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 30 Jan 2013 15:11:53 +0900 Subject: [PATCH 09/40] add mrbgem test runner --- .gitignore | 1 + run_test.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 run_test.rb diff --git a/.gitignore b/.gitignore index f28a84016..55ef3162f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ gem_* gem-* mrb-*.a src/*.o +/tmp diff --git a/run_test.rb b/run_test.rb new file mode 100644 index 000000000..7be23b4d3 --- /dev/null +++ b/run_test.rb @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +DEPEND_GEMS = [] +gemname = File.basename(File.dirname(File.expand_path __FILE__)) + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + if ARGV.first && ARGV.first.include?('iij') + repository, dir = 'https://github.com/iij/mruby.git', 'tmp/iij-mruby' + build_args = ARGV[1, ARGV.size] + end + build_args = ['all', 'test'] if build_args.nil? or build_args.empty? + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gems.clear + conf.gem File.expand_path(File.dirname(__FILE__)) + DEPEND_GEMS.each do |g| + conf.gem g + end +end From f22a72e75471105ed2fd21791b3deabc08e0b8c3 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 30 Jan 2013 17:02:54 +0900 Subject: [PATCH 10/40] update README.md --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 0a148700e..75b79b81d 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,26 @@ mruby-dir ========= Note: mruby-dir requires iij/mruby now. + +## License + +Copyright (c) 2012 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + From 1cde1f24ce96c33ab67ab85544dff28d6e3168eb Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 6 Mar 2013 12:51:04 +0900 Subject: [PATCH 11/40] fix with mruby/mruby support. --- src/dir.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dir.c b/src/dir.c index 9aab0b1cb..850646fcd 100644 --- a/src/dir.c +++ b/src/dir.c @@ -8,6 +8,7 @@ #include "mruby/class.h" #include "mruby/data.h" #include "mruby/string.h" +#include "error.h" #include #include #include @@ -16,6 +17,8 @@ #include #include #include +#include +#include /* with/without IO module */ #ifdef ENABLE_IO From 221296cb556d5eb7ad8c2e1e05535b6bc2458f35 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 6 Mar 2013 12:59:03 +0900 Subject: [PATCH 12/40] update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 75b79b81d..8f133316d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ mruby-dir ========= -Note: mruby-dir requires iij/mruby now. - ## License Copyright (c) 2012 Internet Initiative Japan Inc. From 5e296b24f376b442e463ab847c31dd78f302fcf2 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 6 Mar 2013 12:59:19 +0900 Subject: [PATCH 13/40] remove Makefile --- Makefile | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 80868955b..000000000 --- a/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -GEM := mruby-dir - -include $(MAKEFILE_4_GEM) - -GEM_C_FILES := $(wildcard $(SRC_DIR)/*.c) -GEM_OBJECTS := $(patsubst %.c, %.o, $(GEM_C_FILES)) - -GEM_RB_FILES := $(wildcard $(MRB_DIR)/*.rb) - -gem-all : $(GEM_OBJECTS) gem-c-and-rb-files - -gem-clean : gem-clean-c-and-rb-files - -gem-test : gem-test-c-and-rb-files From 104b69d943488d64d1c33c91612072ebf0b72526 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 13 Mar 2013 22:28:06 +0900 Subject: [PATCH 14/40] rename mrb_str_new2 -> mrb_str_new_cstr --- src/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dir.c b/src/dir.c index 850646fcd..c804f5a4a 100644 --- a/src/dir.c +++ b/src/dir.c @@ -160,7 +160,7 @@ mrb_dir_read(mrb_state *mrb, mrb_value self) } dp = readdir(mdir->dir); if (dp != NULL) { - return mrb_str_new2(mrb, dp->d_name); + return mrb_str_new_cstr(mrb, dp->d_name); } else { return mrb_nil_value(); } From 57296298e93725edd891cda0014bb79c4e93b008 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sat, 27 Apr 2013 09:46:11 +0900 Subject: [PATCH 15/40] put MRB_ prefix before ARGS_XXX macros --- src/dir.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/dir.c b/src/dir.c index c804f5a4a..f2c1471a8 100644 --- a/src/dir.c +++ b/src/dir.c @@ -218,16 +218,17 @@ mrb_mruby_dir_gem_init(mrb_state *mrb) d = mrb_define_class(mrb, "Dir", mrb->object_class); MRB_SET_INSTANCE_TT(d, MRB_TT_DATA); - mrb_define_class_method(mrb, d, "delete", mrb_dir_delete, ARGS_REQ(1)); - mrb_define_class_method(mrb, d, "exist?", mrb_dir_existp, ARGS_REQ(1)); - mrb_define_class_method(mrb, d, "getwd", mrb_dir_getwd, ARGS_NONE()); - mrb_define_class_method(mrb, d, "mkdir", mrb_dir_mkdir, ARGS_REQ(1)|ARGS_OPT(1)); - mrb_define_method(mrb, d, "close", mrb_dir_close, ARGS_NONE()); - mrb_define_method(mrb, d, "initialize", mrb_dir_init, ARGS_REQ(1)); - mrb_define_method(mrb, d, "read", mrb_dir_read, ARGS_NONE()); - mrb_define_method(mrb, d, "rewind", mrb_dir_rewind, ARGS_NONE()); - mrb_define_method(mrb, d, "seek", mrb_dir_seek, ARGS_REQ(1)); - mrb_define_method(mrb, d, "tell", mrb_dir_tell, ARGS_NONE()); + mrb_define_class_method(mrb, d, "delete", mrb_dir_delete, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, d, "exist?", mrb_dir_existp, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, d, "getwd", mrb_dir_getwd, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, d, "mkdir", mrb_dir_mkdir, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + + mrb_define_method(mrb, d, "close", mrb_dir_close, MRB_ARGS_NONE()); + mrb_define_method(mrb, d, "initialize", mrb_dir_init, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, d, "read", mrb_dir_read, MRB_ARGS_NONE()); + mrb_define_method(mrb, d, "rewind", mrb_dir_rewind, MRB_ARGS_NONE()); + mrb_define_method(mrb, d, "seek", mrb_dir_seek, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, d, "tell", mrb_dir_tell, MRB_ARGS_NONE()); } void From ee4fef5127aa3686dfba352ee50e6d420fa2bda7 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 2 May 2013 23:38:50 +0900 Subject: [PATCH 16/40] update run_test.rb --- run_test.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/run_test.rb b/run_test.rb index 7be23b4d3..d9566a2a6 100644 --- a/run_test.rb +++ b/run_test.rb @@ -3,16 +3,11 @@ # mrbgems test runner # -DEPEND_GEMS = [] gemname = File.basename(File.dirname(File.expand_path __FILE__)) if __FILE__ == $0 repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' build_args = ARGV - if ARGV.first && ARGV.first.include?('iij') - repository, dir = 'https://github.com/iij/mruby.git', 'tmp/iij-mruby' - build_args = ARGV[1, ARGV.size] - end build_args = ['all', 'test'] if build_args.nil? or build_args.empty? Dir.mkdir 'tmp' unless File.exist?('tmp') @@ -25,9 +20,7 @@ end MRuby::Build.new do |conf| toolchain :gcc - conf.gems.clear + conf.gembox 'default' + conf.gem File.expand_path(File.dirname(__FILE__)) - DEPEND_GEMS.each do |g| - conf.gem g - end end From 09ea0586ee05b24e9aa0f64ad14b7bd55669f19f Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 20 Aug 2013 17:27:10 +0900 Subject: [PATCH 17/40] catch up with DATA API changes. --- src/dir.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dir.c b/src/dir.c index f2c1471a8..26021c275 100644 --- a/src/dir.c +++ b/src/dir.c @@ -69,15 +69,16 @@ mrb_dir_init(mrb_state *mrb, mrb_value self) mrb_value path; char *cpath; - mdir = (struct mrb_dir *)mrb_get_datatype(mrb, self, &mrb_dir_type); + mdir = (struct mrb_dir *)DATA_PTR(self); if (mdir) { mrb_dir_free(mrb, mdir); } + DATA_TYPE(self) = &mrb_dir_type; + DATA_PTR(self) = NULL; mdir = (struct mrb_dir *)mrb_malloc(mrb, sizeof(*mdir)); mdir->dir = NULL; DATA_PTR(self) = mdir; - DATA_TYPE(self) = &mrb_dir_type; mrb_get_args(mrb, "S", &path); cpath = mrb_str_to_cstr(mrb, path); From 0380865a551ba69d6e0e015883132c29aa791acd Mon Sep 17 00:00:00 2001 From: Takuya ASADA Date: Thu, 14 Nov 2013 03:08:43 -0800 Subject: [PATCH 18/40] add chdir --- src/dir.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/dir.c b/src/dir.c index 26021c275..14108f8de 100644 --- a/src/dir.c +++ b/src/dir.c @@ -148,6 +148,20 @@ mrb_dir_mkdir(mrb_state *mrb, mrb_value klass) return mrb_fixnum_value(0); } +mrb_value +mrb_dir_chdir(mrb_state *mrb, mrb_value klass) +{ + mrb_value spath; + char *path; + + mrb_get_args(mrb, "S", &spath); + path = mrb_str_to_cstr(mrb, spath); + if (chdir(path) == -1) { + mrb_sys_fail(mrb, path); + } + return mrb_fixnum_value(0); +} + mrb_value mrb_dir_read(mrb_state *mrb, mrb_value self) { @@ -223,6 +237,7 @@ mrb_mruby_dir_gem_init(mrb_state *mrb) mrb_define_class_method(mrb, d, "exist?", mrb_dir_existp, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, d, "getwd", mrb_dir_getwd, MRB_ARGS_NONE()); mrb_define_class_method(mrb, d, "mkdir", mrb_dir_mkdir, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, d, "chdir", mrb_dir_chdir, MRB_ARGS_REQ(1)); mrb_define_method(mrb, d, "close", mrb_dir_close, MRB_ARGS_NONE()); mrb_define_method(mrb, d, "initialize", mrb_dir_init, MRB_ARGS_REQ(1)); From 12dce91db8d1c4d0b93626454d6eba1ded94e069 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sat, 16 Nov 2013 14:28:40 +0900 Subject: [PATCH 19/40] support Dir.chdir with block --- mrblib/dir.rb | 15 +++++++++++++++ src/dir.c | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/mrblib/dir.rb b/mrblib/dir.rb index b53a7102a..e00f8290a 100644 --- a/mrblib/dir.rb +++ b/mrblib/dir.rb @@ -40,6 +40,21 @@ class Dir end end + def self.chdir(path, &block) + my = self # workaround for https://github.com/mruby/mruby/issues/1579 + if block + wd = self.getwd + begin + self._chdir(path) + block.call + ensure + my._chdir(wd) + end + else + self._chdir(path) + end + end + class << self alias exists? exist? alias pwd getwd diff --git a/src/dir.c b/src/dir.c index 14108f8de..97e0c4fc9 100644 --- a/src/dir.c +++ b/src/dir.c @@ -237,7 +237,7 @@ mrb_mruby_dir_gem_init(mrb_state *mrb) mrb_define_class_method(mrb, d, "exist?", mrb_dir_existp, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, d, "getwd", mrb_dir_getwd, MRB_ARGS_NONE()); mrb_define_class_method(mrb, d, "mkdir", mrb_dir_mkdir, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); - mrb_define_class_method(mrb, d, "chdir", mrb_dir_chdir, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, d, "_chdir", mrb_dir_chdir, MRB_ARGS_REQ(1)); mrb_define_method(mrb, d, "close", mrb_dir_close, MRB_ARGS_NONE()); mrb_define_method(mrb, d, "initialize", mrb_dir_init, MRB_ARGS_REQ(1)); From a036be21bc8dfe86eafbd5d33ec9cc9104edf60e Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sat, 16 Nov 2013 14:36:31 +0900 Subject: [PATCH 20/40] fix chdir (pass the current directory) --- mrblib/dir.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/dir.rb b/mrblib/dir.rb index e00f8290a..065ca1c22 100644 --- a/mrblib/dir.rb +++ b/mrblib/dir.rb @@ -46,7 +46,7 @@ class Dir wd = self.getwd begin self._chdir(path) - block.call + block.call(path) ensure my._chdir(wd) end From d7e880d9b950d5726a256fcd4b319130304d6f73 Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Mon, 2 Dec 2013 12:15:21 +0100 Subject: [PATCH 21/40] Fix for compilation under Win/MinGW --- src/dir.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dir.c b/src/dir.c index 97e0c4fc9..19bb5834f 100644 --- a/src/dir.c +++ b/src/dir.c @@ -142,7 +142,11 @@ mrb_dir_mkdir(mrb_state *mrb, mrb_value klass) mode = 0777; mrb_get_args(mrb, "S|i", &spath, &mode); path = mrb_str_to_cstr(mrb, spath); +#ifndef _WIN32 if (mkdir(path, mode) == -1) { +#else + if (mkdir(path) == -1) { +#endif mrb_sys_fail(mrb, path); } return mrb_fixnum_value(0); From 97685355825fc169440cd44d3c24f040559a757c Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Tue, 10 Dec 2013 14:33:36 +0100 Subject: [PATCH 22/40] Made compatible with VisualStudio --- mrbgem.rake | 7 +++ src/Win/dirent.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++ src/Win/dirent.h | 50 ++++++++++++++++ src/dir.c | 28 ++++++++- 4 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 src/Win/dirent.c create mode 100644 src/Win/dirent.h diff --git a/mrbgem.rake b/mrbgem.rake index 670298049..fd5fe3781 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -3,4 +3,11 @@ MRuby::Gem::Specification.new('mruby-dir') do |spec| spec.authors = 'Internet Initiative Japan Inc.' spec.cc.include_paths << "#{build.root}/src" + + case RUBY_PLATFORM + when /mingw|mswin/ + spec.objs += Dir.glob("#{dir}/src/Win/*.{c,cpp,m,asm,S}").map { |f| + objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) + } + end end diff --git a/src/Win/dirent.c b/src/Win/dirent.c new file mode 100644 index 000000000..12a2547bf --- /dev/null +++ b/src/Win/dirent.c @@ -0,0 +1,148 @@ +/* + + Implementation of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003 and July 2012. + Rights: See end of file. + +*/ + +#include "dirent.h" +#include +#include /* _findfirst and _findnext set errno iff they return -1 */ +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ + +struct DIR +{ + handle_type handle; /* -1 for failed rewind */ + struct _finddata_t info; + struct dirent result; /* d_name null iff first time */ + char *name; /* null-terminated char string */ +}; + +DIR *opendir(const char *name) +{ + DIR *dir = 0; + + if(name && name[0]) + { + size_t base_length = strlen(name); + const char *all = /* search pattern must end with suitable wildcard */ + strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if((dir = (DIR *) malloc(sizeof *dir)) != 0 && + (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) + { + strcat(strcpy(dir->name, name), all); + + if((dir->handle = + (handle_type) _findfirst(dir->name, &dir->info)) != -1) + { + dir->result.d_name = 0; + } + else /* rollback */ + { + free(dir->name); + free(dir); + dir = 0; + } + } + else /* rollback */ + { + free(dir); + dir = 0; + errno = ENOMEM; + } + } + else + { + errno = EINVAL; + } + + return dir; +} + +int closedir(DIR *dir) +{ + int result = -1; + + if(dir) + { + if(dir->handle != -1) + { + result = _findclose(dir->handle); + } + + free(dir->name); + free(dir); + } + + if(result == -1) /* map all errors to EBADF */ + { + errno = EBADF; + } + + return result; +} + +struct dirent *readdir(DIR *dir) +{ + struct dirent *result = 0; + + if(dir && dir->handle != -1) + { + if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) + { + result = &dir->result; + result->d_name = dir->info.name; + } + } + else + { + errno = EBADF; + } + + return result; +} + +void rewinddir(DIR *dir) +{ + if(dir && dir->handle != -1) + { + _findclose(dir->handle); + dir->handle = (handle_type) _findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + } + else + { + errno = EBADF; + } +} + +#ifdef __cplusplus +} +#endif + +/* + + Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + +*/ diff --git a/src/Win/dirent.h b/src/Win/dirent.h new file mode 100644 index 000000000..a02a0d828 --- /dev/null +++ b/src/Win/dirent.h @@ -0,0 +1,50 @@ +#ifndef DIRENT_INCLUDED +#define DIRENT_INCLUDED + +/* + + Declaration of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + Rights: See end of file. + +*/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct DIR DIR; + +struct dirent +{ + char *d_name; +}; + +DIR *opendir(const char *); +int closedir(DIR *); +struct dirent *readdir(DIR *); +void rewinddir(DIR *); + +/* + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dir.c b/src/dir.c index 19bb5834f..e80a5886e 100644 --- a/src/dir.c +++ b/src/dir.c @@ -10,14 +10,26 @@ #include "mruby/string.h" #include "error.h" #include -#include +#if defined(_WIN32) || defined(_WIN64) + #define MAXPATHLEN 1024 + #define PATH_MAX MAX_PATH + #define S_ISDIR(B) ((B)&_S_IFDIR) + #include "Win/dirent.h" + #include + #define rmdir _rmdir + #define getcwd _getcwd + #define mkdir _mkdir + #define chdir _chdir +#else + #include + #include + #include +#endif #include -#include #include #include #include #include -#include #include /* with/without IO module */ @@ -202,6 +214,10 @@ mrb_dir_rewind(mrb_state *mrb, mrb_value self) mrb_value mrb_dir_seek(mrb_state *mrb, mrb_value self) { + #if defined(_WIN32) || (_WIN64) + mrb_raise(mrb, E_RUNTIME_ERROR, "dirseek() unreliable on Win platforms"); + return self; + #else struct mrb_dir *mdir; mrb_int pos; @@ -213,11 +229,16 @@ mrb_dir_seek(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "i", &pos); seekdir(mdir->dir, (long)pos); return self; + #endif } mrb_value mrb_dir_tell(mrb_state *mrb, mrb_value self) { + #if defined(_WIN32) || (_WIN64) + mrb_raise(mrb, E_RUNTIME_ERROR, "dirtell() unreliable on Win platforms"); + return mrb_fixnum_value(0); + #else struct mrb_dir *mdir; mrb_int pos; @@ -228,6 +249,7 @@ mrb_dir_tell(mrb_state *mrb, mrb_value self) } pos = (mrb_int)telldir(mdir->dir); return mrb_fixnum_value(pos); + #endif } void From 4800836dd46b219b626a57080c57a15952b8fd0c Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 14 Mar 2014 10:06:14 +0900 Subject: [PATCH 23/40] On Windows platforms, users must agree on addional license. --- README.md | 13 +++++++++++++ mrbgem.rake | 4 +++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f133316d..f40f03866 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,16 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +- On Windows platforms, you must agree on addional license too: + +Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that this copyright and permissions notice appear in all copies and +derivatives. + +This software is supplied "as is" without express or implied warranty. + +But that said, if there are any problems please get in touch. diff --git a/mrbgem.rake b/mrbgem.rake index fd5fe3781..740671132 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -1,11 +1,13 @@ MRuby::Gem::Specification.new('mruby-dir') do |spec| spec.license = 'MIT' - spec.authors = 'Internet Initiative Japan Inc.' + spec.authors = [ 'Internet Initiative Japan Inc.' ] spec.cc.include_paths << "#{build.root}/src" case RUBY_PLATFORM when /mingw|mswin/ + spec.license = 'MIT and MIT-like license' + spec.authors += [ 'Kevlin Henney' ] spec.objs += Dir.glob("#{dir}/src/Win/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } From a252681f391d117a7a0ba1686fcdbb5238e393c1 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Apr 2014 11:24:07 +0900 Subject: [PATCH 24/40] Create .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..09fa3368f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb" From 2a0423c11dedfc56d4760c7be3d9021cda2bb063 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Apr 2014 11:30:38 +0900 Subject: [PATCH 25/40] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 09fa3368f..ffe227284 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,2 @@ script: - - "ruby run_test.rb" + - "ruby run_test.rb all test" From 627282a5f6da88f7ab94a6aa25c7a79c6461c69f Mon Sep 17 00:00:00 2001 From: windwiny Date: Wed, 7 May 2014 20:43:12 +0800 Subject: [PATCH 26/40] compatible 32 bit windows --- src/dir.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dir.c b/src/dir.c index e80a5886e..70a6e01a8 100644 --- a/src/dir.c +++ b/src/dir.c @@ -12,7 +12,9 @@ #include #if defined(_WIN32) || defined(_WIN64) #define MAXPATHLEN 1024 + #if !defined(PATH_MAX) #define PATH_MAX MAX_PATH + #endif #define S_ISDIR(B) ((B)&_S_IFDIR) #include "Win/dirent.h" #include From 0d378be34e263b6477d17b655eb84785adaf2b80 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 17 Jun 2014 11:33:10 +0900 Subject: [PATCH 27/40] tests and documentation. --- README.md | 18 ++++++++ test/dir.rb | 110 +++++++++++++++++++++++++++++++++++++++++++++++ test/dirtest.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 test/dirtest.c diff --git a/README.md b/README.md index f40f03866..d7953036d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,24 @@ mruby-dir ========= +Dir class for mruby. Supported methods are: + +`.chdir` +`.delete` +`.entries` +`.exist?` +`.foreach` +`.getwd` +`.mkdir` +`.open` +`#close` +`#each` +`#read` +`#rewind` +`#seek` +`#tell` + + ## License Copyright (c) 2012 Internet Initiative Japan Inc. diff --git a/test/dir.rb b/test/dir.rb index e69de29bb..95acf7725 100644 --- a/test/dir.rb +++ b/test/dir.rb @@ -0,0 +1,110 @@ +# Note: testing telldir(3) and seekdir(3) in portable manner is very hard. + +assert('Dir') do + assert_equal(Class, Addrinfo.class) +end + +assert('DirTest.setup') do + DirTest.setup +end + +assert('Dir.chdir') do + assert_equal 0, Dir.chdir(DirTest.sandbox) +end + +assert('Dir.entries') do + a = Dir.entries(DirTest.sandbox) + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir.exist?') do + assert_true Dir.exist?(DirTest.sandbox) + assert_false Dir.exist?(DirTest.sandbox + "/nosuchdir") +end + +assert('Dir.foreach') do + a = [] + Dir.foreach(DirTest.sandbox) { |s| a << s } + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir.getwd') do + s = Dir.getwd + assert_true s.kind_of? String +end + +assert('Dir.mkdir') do + m1 = DirTest.sandbox + "/mkdir1" + m2 = DirTest.sandbox + "/mkdir2" + assert_equal 0, Dir.mkdir(m1) + assert_equal 0, Dir.mkdir(m2, 0765) +end + +assert('Dir.delete') do + s = DirTest.sandbox + "/delete" + Dir.mkdir(s) + assert_true Dir.exist?(s) + + Dir.delete(s) + assert_false Dir.exist?(s) +end + +assert('Dir.open') do + a = [] + Dir.open(DirTest.sandbox) { |d| + d.each { |s| a << s } + } + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir#initialize and Dir#close') do + d = Dir.new(".") + assert_true d.instance_of? Dir + assert_nil d.close +end + +assert('Dir#close') do + d = Dir.new(".") +end + +assert('Dir#each') do + a = [] + d = Dir.open(DirTest.sandbox) + d.each { |s| a << s } + d.close + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir#read') do + a = [] + d = Dir.open(DirTest.sandbox) + while s = d.read + a << s + end + d.close + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('Dir#rewind') do + d = Dir.open(DirTest.sandbox) + while d.read; end + + assert_equal d, d.rewind + + a = [] + while s = d.read + a << s + end + d.close + assert_true a.include? "a" + assert_true a.include? "b" +end + +assert('DirTest.teardown') do + DirTest.teardown +end diff --git a/test/dirtest.c b/test/dirtest.c new file mode 100644 index 000000000..ca5e9f19a --- /dev/null +++ b/test/dirtest.c @@ -0,0 +1,114 @@ +#include +#include + +#include +#include + +#include +#include +#include + +#include "mruby.h" +#include "mruby/string.h" +#include "mruby/variable.h" + + +mrb_value +mrb_dirtest_setup(mrb_state *mrb, mrb_value klass) +{ + mrb_value s; + char buf[1024]; + const char *aname = "a"; + const char *bname = "b"; + + /* save current working directory */ + if (getcwd(buf, sizeof(buf)) == NULL) { + mrb_raise(mrb, E_RUNTIME_ERROR, "getcwd() failed"); + } + mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "pwd"), mrb_str_new_cstr(mrb, buf)); + + /* create sandbox */ + snprintf(buf, sizeof(buf), "%smruby-dir-test.XXXXXX", P_tmpdir); + if (mkdtemp(buf) == NULL) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdtemp(%S) failed", mrb_str_new_cstr(mrb, buf)); + } + s = mrb_str_new_cstr(mrb, buf); + mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "sandbox"), s); + + /* go to sandbox */ + if (chdir(buf) == -1) { + rmdir(buf); + mrb_raisef(mrb, E_RUNTIME_ERROR, "chdir(%S) failed", s); + } + + /* make some directories in the sandbox */ + if (mkdir(aname, 0) == -1) { + chdir(".."); + rmdir(buf); + mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdir(%S) failed", mrb_str_new_cstr(mrb, aname)); + } + if (mkdir(bname, 0) == -1) { + rmdir(aname); + chdir(".."); + rmdir(buf); + mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdir(%S) failed", mrb_str_new_cstr(mrb, bname)); + } + + return mrb_true_value(); +} + +mrb_value +mrb_dirtest_teardown(mrb_state *mrb, mrb_value klass) +{ + mrb_value d, sandbox; + DIR *dirp; + struct dirent *dp; + const char *path; + + /* cleanup sandbox */ + sandbox = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "sandbox")); + path = mrb_str_to_cstr(mrb, sandbox); + + dirp = opendir(path); + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) + continue; + if (rmdir(dp->d_name) == -1) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "rmdir(%S) failed", mrb_str_new_cstr(mrb, dp->d_name)); + } + } + closedir(dirp); + + /* back to original pwd */ + d = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "pwd")); + path = mrb_str_to_cstr(mrb, d); + if (chdir(path) == -1) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "chdir(%S) failed", d); + } + + /* remove sandbox directory */ + sandbox = mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "sandbox")); + path = mrb_str_to_cstr(mrb, sandbox); + if (rmdir(path) == -1) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "rmdir(%S) failed", sandbox); + } + + return mrb_true_value(); +} + +mrb_value +mrb_dirtest_sandbox(mrb_state *mrb, mrb_value klass) +{ + return mrb_cv_get(mrb, klass, mrb_intern_cstr(mrb, "sandbox")); +} + +void +mrb_mruby_dir_gem_test(mrb_state *mrb) +{ + struct RClass *c = mrb_define_module(mrb, "DirTest"); + + mrb_define_class_method(mrb, c, "sandbox", mrb_dirtest_sandbox, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, c, "setup", mrb_dirtest_setup, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, c, "teardown", mrb_dirtest_teardown, MRB_ARGS_NONE()); +} + From 14e325348bf504d4cc7e275536004ddad2c99032 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 17 Jun 2014 11:37:57 +0900 Subject: [PATCH 28/40] copy-and-paste bug... --- test/dir.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dir.rb b/test/dir.rb index 95acf7725..9cc33eee2 100644 --- a/test/dir.rb +++ b/test/dir.rb @@ -1,7 +1,7 @@ # Note: testing telldir(3) and seekdir(3) in portable manner is very hard. assert('Dir') do - assert_equal(Class, Addrinfo.class) + assert_equal(Class, Dir.class) end assert('DirTest.setup') do From 193c82174f6cb5cf1f03a04dd4932dd8fb8c0bf0 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 17 Jun 2014 11:47:16 +0900 Subject: [PATCH 29/40] P_tmpdir does not have trailing / on Linux. --- test/dirtest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dirtest.c b/test/dirtest.c index ca5e9f19a..070f23a82 100644 --- a/test/dirtest.c +++ b/test/dirtest.c @@ -28,7 +28,7 @@ mrb_dirtest_setup(mrb_state *mrb, mrb_value klass) mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "pwd"), mrb_str_new_cstr(mrb, buf)); /* create sandbox */ - snprintf(buf, sizeof(buf), "%smruby-dir-test.XXXXXX", P_tmpdir); + snprintf(buf, sizeof(buf), "%s/mruby-dir-test.XXXXXX", P_tmpdir); if (mkdtemp(buf) == NULL) { mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdtemp(%S) failed", mrb_str_new_cstr(mrb, buf)); } From 6cc24d07935a265df6edad4352ece1b1c3aca8dc Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 20 Jun 2014 15:25:10 +0900 Subject: [PATCH 30/40] add tests for #tell and #seek. --- test/dir.rb | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/dir.rb b/test/dir.rb index 9cc33eee2..cb1f1e31b 100644 --- a/test/dir.rb +++ b/test/dir.rb @@ -1,5 +1,3 @@ -# Note: testing telldir(3) and seekdir(3) in portable manner is very hard. - assert('Dir') do assert_equal(Class, Dir.class) end @@ -105,6 +103,26 @@ assert('Dir#rewind') do assert_true a.include? "b" end +# Note: behaviors of seekdir(3) and telldir(3) are so platform-dependent +# that we cannot write portable tests here. + +assert('Dir#tell') do + n = nil + Dir.open(DirTest.sandbox) { |d| + n = d.tell + } + assert_true n.is_a? Integer +end + +assert('Dir#seek') do + d1 = Dir.open(DirTest.sandbox) + d1.read + n = d1.tell + d1.read + d2 = d1.seek(n) + assert_equal d1, d2 +end + assert('DirTest.teardown') do DirTest.teardown end From 5542f7b0fc2e85e0ee3d4e61828c47621d77f7ca Mon Sep 17 00:00:00 2001 From: furunkel Date: Mon, 1 Jun 2015 21:06:59 +0200 Subject: [PATCH 31/40] Use _WIN32 and _WIN64 to detect Windows instead of RUBY_PLATFORM --- mrbgem.rake | 13 ++----------- src/Win/dirent.h | 50 ------------------------------------------------ src/dir.c | 2 +- 3 files changed, 3 insertions(+), 62 deletions(-) delete mode 100644 src/Win/dirent.h diff --git a/mrbgem.rake b/mrbgem.rake index 740671132..10864c81c 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -1,15 +1,6 @@ MRuby::Gem::Specification.new('mruby-dir') do |spec| - spec.license = 'MIT' - spec.authors = [ 'Internet Initiative Japan Inc.' ] + spec.license = 'MIT and MIT-like license' + spec.authors = [ 'Internet Initiative Japan Inc.', 'Kevlin Henney'] spec.cc.include_paths << "#{build.root}/src" - - case RUBY_PLATFORM - when /mingw|mswin/ - spec.license = 'MIT and MIT-like license' - spec.authors += [ 'Kevlin Henney' ] - spec.objs += Dir.glob("#{dir}/src/Win/*.{c,cpp,m,asm,S}").map { |f| - objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) - } - end end diff --git a/src/Win/dirent.h b/src/Win/dirent.h deleted file mode 100644 index a02a0d828..000000000 --- a/src/Win/dirent.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef DIRENT_INCLUDED -#define DIRENT_INCLUDED - -/* - - Declaration of POSIX directory browsing functions and types for Win32. - - Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) - History: Created March 1997. Updated June 2003. - Rights: See end of file. - -*/ - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef struct DIR DIR; - -struct dirent -{ - char *d_name; -}; - -DIR *opendir(const char *); -int closedir(DIR *); -struct dirent *readdir(DIR *); -void rewinddir(DIR *); - -/* - - Copyright Kevlin Henney, 1997, 2003. All rights reserved. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that this copyright and permissions notice appear in all copies and - derivatives. - - This software is supplied "as is" without express or implied warranty. - - But that said, if there are any problems please get in touch. - -*/ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/dir.c b/src/dir.c index 70a6e01a8..00658debd 100644 --- a/src/dir.c +++ b/src/dir.c @@ -16,7 +16,7 @@ #define PATH_MAX MAX_PATH #endif #define S_ISDIR(B) ((B)&_S_IFDIR) - #include "Win/dirent.h" + #include "Win/dirent.c" #include #define rmdir _rmdir #define getcwd _getcwd From 9eec22cda1e4bf3029b3d8512ea1cb61f57b7465 Mon Sep 17 00:00:00 2001 From: furunkel Date: Mon, 1 Jun 2015 21:16:25 +0200 Subject: [PATCH 32/40] Add missing declarations --- src/Win/dirent.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Win/dirent.c b/src/Win/dirent.c index 12a2547bf..98728bcf7 100644 --- a/src/Win/dirent.c +++ b/src/Win/dirent.c @@ -8,7 +8,6 @@ */ -#include "dirent.h" #include #include /* _findfirst and _findnext set errno iff they return -1 */ #include @@ -21,6 +20,11 @@ extern "C" typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ +struct dirent +{ + char *d_name; +}; + struct DIR { handle_type handle; /* -1 for failed rewind */ @@ -29,6 +33,8 @@ struct DIR char *name; /* null-terminated char string */ }; +typedef struct DIR DIR; + DIR *opendir(const char *name) { DIR *dir = 0; From 6e30353dfd6247828b0c006b166a7696ed7882b5 Mon Sep 17 00:00:00 2001 From: xuejianqing Date: Thu, 13 Aug 2015 17:33:45 +0800 Subject: [PATCH 33/40] disable dir_seek and dir_tell on android platform --- src/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dir.c b/src/dir.c index 00658debd..0f55ed93d 100644 --- a/src/dir.c +++ b/src/dir.c @@ -216,7 +216,7 @@ mrb_dir_rewind(mrb_state *mrb, mrb_value self) mrb_value mrb_dir_seek(mrb_state *mrb, mrb_value self) { - #if defined(_WIN32) || (_WIN64) + #if defined(_WIN32) || defined(_WIN64) || defined(__android__) mrb_raise(mrb, E_RUNTIME_ERROR, "dirseek() unreliable on Win platforms"); return self; #else @@ -237,7 +237,7 @@ mrb_dir_seek(mrb_state *mrb, mrb_value self) mrb_value mrb_dir_tell(mrb_state *mrb, mrb_value self) { - #if defined(_WIN32) || (_WIN64) + #if defined(_WIN32) || defined(_WIN64) || defined(__android__) mrb_raise(mrb, E_RUNTIME_ERROR, "dirtell() unreliable on Win platforms"); return mrb_fixnum_value(0); #else From 3501af9ba22cd0860a023f7646b13454a5ed7b9e Mon Sep 17 00:00:00 2001 From: takahashim Date: Thu, 3 Dec 2015 00:10:19 +0900 Subject: [PATCH 34/40] add conf.enable_test into build_config.rb --- run_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/run_test.rb b/run_test.rb index d9566a2a6..30fbad316 100644 --- a/run_test.rb +++ b/run_test.rb @@ -21,6 +21,7 @@ end MRuby::Build.new do |conf| toolchain :gcc conf.gembox 'default' + conf.enable_test conf.gem File.expand_path(File.dirname(__FILE__)) end From 6140cb158d2a1c6aa6a59ebcf2574e2925f97696 Mon Sep 17 00:00:00 2001 From: takahashim Date: Thu, 3 Dec 2015 15:25:12 +0900 Subject: [PATCH 35/40] use NotImplementedError instead of RuntimeError for Win --- src/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dir.c b/src/dir.c index 0f55ed93d..1ea99eccf 100644 --- a/src/dir.c +++ b/src/dir.c @@ -217,7 +217,7 @@ mrb_value mrb_dir_seek(mrb_state *mrb, mrb_value self) { #if defined(_WIN32) || defined(_WIN64) || defined(__android__) - mrb_raise(mrb, E_RUNTIME_ERROR, "dirseek() unreliable on Win platforms"); + mrb_raise(mrb, E_NOTIMP_ERROR, "dirseek() unreliable on Win platforms"); return self; #else struct mrb_dir *mdir; @@ -238,7 +238,7 @@ mrb_value mrb_dir_tell(mrb_state *mrb, mrb_value self) { #if defined(_WIN32) || defined(_WIN64) || defined(__android__) - mrb_raise(mrb, E_RUNTIME_ERROR, "dirtell() unreliable on Win platforms"); + mrb_raise(mrb, E_NOTIMP_ERROR, "dirtell() unreliable on Win platforms"); return mrb_fixnum_value(0); #else struct mrb_dir *mdir; From 71f21845caacde2c979a79611eaf2cd904c2819e Mon Sep 17 00:00:00 2001 From: takahashim Date: Thu, 3 Dec 2015 00:45:51 +0900 Subject: [PATCH 36/40] fix test for windows * _mkdir() has only one argument * use mktemp && mkdir instead of mkdtemp * use _getcwd instead of P_tmpdir (sandbox is on current dir) * test for Dir#tell and Dir#seek: skip when NotImplementedError --- test/dir.rb | 24 ++++++++++++++++-------- test/dirtest.c | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/test/dir.rb b/test/dir.rb index cb1f1e31b..3b521b444 100644 --- a/test/dir.rb +++ b/test/dir.rb @@ -108,19 +108,27 @@ end assert('Dir#tell') do n = nil - Dir.open(DirTest.sandbox) { |d| - n = d.tell - } - assert_true n.is_a? Integer + begin + Dir.open(DirTest.sandbox) { |d| + n = d.tell + } + assert_true n.is_a? Integer + rescue NotImplementedError => e + skip e.message + end end assert('Dir#seek') do d1 = Dir.open(DirTest.sandbox) d1.read - n = d1.tell - d1.read - d2 = d1.seek(n) - assert_equal d1, d2 + begin + n = d1.tell + d1.read + d2 = d1.seek(n) + assert_equal d1, d2 + rescue NotImplementedError => e + skip e.message + end end assert('DirTest.teardown') do diff --git a/test/dirtest.c b/test/dirtest.c index 070f23a82..f73af8468 100644 --- a/test/dirtest.c +++ b/test/dirtest.c @@ -28,10 +28,17 @@ mrb_dirtest_setup(mrb_state *mrb, mrb_value klass) mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "pwd"), mrb_str_new_cstr(mrb, buf)); /* create sandbox */ +#if defined(_WIN32) || defined(_WIN64) + snprintf(buf, sizeof(buf), "%s\\mruby-dir-test.XXXXXX", _getcwd(NULL,0)); + if ((mktemp(buf) == NULL) || mkdir(buf) != 0) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdtemp(%S) failed", mrb_str_new_cstr(mrb, buf)); + } +#else snprintf(buf, sizeof(buf), "%s/mruby-dir-test.XXXXXX", P_tmpdir); if (mkdtemp(buf) == NULL) { mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdtemp(%S) failed", mrb_str_new_cstr(mrb, buf)); } +#endif s = mrb_str_new_cstr(mrb, buf); mrb_cv_set(mrb, klass, mrb_intern_cstr(mrb, "sandbox"), s); @@ -42,12 +49,20 @@ mrb_dirtest_setup(mrb_state *mrb, mrb_value klass) } /* make some directories in the sandbox */ +#if defined(_WIN32) || defined(_WIN64) + if (mkdir(aname) == -1) { +#else if (mkdir(aname, 0) == -1) { +#endif chdir(".."); rmdir(buf); mrb_raisef(mrb, E_RUNTIME_ERROR, "mkdir(%S) failed", mrb_str_new_cstr(mrb, aname)); } +#if defined(_WIN32) || defined(_WIN64) + if (mkdir(bname) == -1) { +#else if (mkdir(bname, 0) == -1) { +#endif rmdir(aname); chdir(".."); rmdir(buf); From e9c4b10446d5c3749f8bb851afa23f12e6f4fda8 Mon Sep 17 00:00:00 2001 From: Uchio KONDO Date: Fri, 10 Jun 2016 15:59:20 +0900 Subject: [PATCH 37/40] Implement Dir.chroot on mruby --- src/dir.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/dir.c b/src/dir.c index 1ea99eccf..00f2f0296 100644 --- a/src/dir.c +++ b/src/dir.c @@ -180,6 +180,29 @@ mrb_dir_chdir(mrb_state *mrb, mrb_value klass) return mrb_fixnum_value(0); } +mrb_value +mrb_dir_chroot(mrb_state *mrb, mrb_value self) +{ + #if defined(_WIN32) || defined(_WIN64) || defined(__android__) + mrb_raise(mrb, E_NOTIMP_ERROR, "chroot() unreliable on Win platforms"); + return mrb_fixnum_value(0); + #else + mrb_value spath; + char *path; + int res; + + mrb_get_args(mrb, "S", &spath); + path = mrb_str_to_cstr(mrb, spath); + res = chroot(path); + if (res == -1) { + perror("chroot"); + mrb_sys_fail(mrb, path); + } + + return mrb_fixnum_value(res); + #endif +} + mrb_value mrb_dir_read(mrb_state *mrb, mrb_value self) { @@ -266,6 +289,7 @@ mrb_mruby_dir_gem_init(mrb_state *mrb) mrb_define_class_method(mrb, d, "getwd", mrb_dir_getwd, MRB_ARGS_NONE()); mrb_define_class_method(mrb, d, "mkdir", mrb_dir_mkdir, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); mrb_define_class_method(mrb, d, "_chdir", mrb_dir_chdir, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, d, "chroot", mrb_dir_chroot, MRB_ARGS_REQ(1)); mrb_define_method(mrb, d, "close", mrb_dir_close, MRB_ARGS_NONE()); mrb_define_method(mrb, d, "initialize", mrb_dir_init, MRB_ARGS_REQ(1)); From 7318ae59775b60b897f75f2f444ba4aee8d31ee2 Mon Sep 17 00:00:00 2001 From: Uchio KONDO Date: Mon, 13 Jun 2016 09:42:16 +0900 Subject: [PATCH 38/40] Remove perror --- src/dir.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dir.c b/src/dir.c index 00f2f0296..e958ced8a 100644 --- a/src/dir.c +++ b/src/dir.c @@ -195,7 +195,6 @@ mrb_dir_chroot(mrb_state *mrb, mrb_value self) path = mrb_str_to_cstr(mrb, spath); res = chroot(path); if (res == -1) { - perror("chroot"); mrb_sys_fail(mrb, path); } From b1ccf9764be66a29d2c89aa60876fee4ab5f3664 Mon Sep 17 00:00:00 2001 From: masahino Date: Thu, 15 Dec 2016 21:34:27 +0900 Subject: [PATCH 39/40] Add pointer casting --- src/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dir.c b/src/dir.c index e958ced8a..02fff19c2 100644 --- a/src/dir.c +++ b/src/dir.c @@ -48,7 +48,7 @@ struct mrb_dir { void mrb_dir_free(mrb_state *mrb, void *ptr) { - struct mrb_dir *mdir = ptr; + struct mrb_dir *mdir = (struct mrb_dir *)ptr; if (mdir->dir) { closedir(mdir->dir); From 89dceefa1250fb1ae868d4cb52498e9e24293cd1 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 14 Sep 2018 15:49:36 +0900 Subject: [PATCH 40/40] s/__android__/__ANDROID__/. fixes #15. mruby core uses __ANDROID__ to know whether the target system is Android or not (in mrbgems/mruby-math). --- src/dir.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dir.c b/src/dir.c index 02fff19c2..acfe4d246 100644 --- a/src/dir.c +++ b/src/dir.c @@ -183,8 +183,8 @@ mrb_dir_chdir(mrb_state *mrb, mrb_value klass) mrb_value mrb_dir_chroot(mrb_state *mrb, mrb_value self) { - #if defined(_WIN32) || defined(_WIN64) || defined(__android__) - mrb_raise(mrb, E_NOTIMP_ERROR, "chroot() unreliable on Win platforms"); + #if defined(_WIN32) || defined(_WIN64) || defined(__ANDROID__) + mrb_raise(mrb, E_NOTIMP_ERROR, "chroot() unreliable on your system"); return mrb_fixnum_value(0); #else mrb_value spath; @@ -238,8 +238,8 @@ mrb_dir_rewind(mrb_state *mrb, mrb_value self) mrb_value mrb_dir_seek(mrb_state *mrb, mrb_value self) { - #if defined(_WIN32) || defined(_WIN64) || defined(__android__) - mrb_raise(mrb, E_NOTIMP_ERROR, "dirseek() unreliable on Win platforms"); + #if defined(_WIN32) || defined(_WIN64) || defined(__ANDROID__) + mrb_raise(mrb, E_NOTIMP_ERROR, "dirseek() unreliable on your system"); return self; #else struct mrb_dir *mdir; @@ -259,8 +259,8 @@ mrb_dir_seek(mrb_state *mrb, mrb_value self) mrb_value mrb_dir_tell(mrb_state *mrb, mrb_value self) { - #if defined(_WIN32) || defined(_WIN64) || defined(__android__) - mrb_raise(mrb, E_NOTIMP_ERROR, "dirtell() unreliable on Win platforms"); + #if defined(_WIN32) || defined(_WIN64) || defined(__ANDROID__) + mrb_raise(mrb, E_NOTIMP_ERROR, "dirtell() unreliable on your system"); return mrb_fixnum_value(0); #else struct mrb_dir *mdir;