From e8ca5e516983fe720ec46887744f0d21b8f16ce1 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Mon, 1 Apr 2013 09:12:01 +0900 Subject: initial commit --- .gitignore | 1 + README.md | 5 + include/mruby/ext/io.h | 60 ++++ mrbgem.rake | 6 + mrblib/file.rb | 108 +++++++ mrblib/file_constants.rb | 31 ++ mrblib/io.rb | 271 +++++++++++++++++ run_test.rb | 33 +++ src/file.c | 294 ++++++++++++++++++ src/file_test.c | 307 +++++++++++++++++++ src/io.c | 755 +++++++++++++++++++++++++++++++++++++++++++++++ src/mruby_io_gem.c | 20 ++ test/file.rb | 75 +++++ test/file_test.rb | 90 ++++++ test/io.rb | 237 +++++++++++++++ test/mruby_io_test.c | 94 ++++++ 16 files changed, 2387 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 include/mruby/ext/io.h create mode 100644 mrbgem.rake create mode 100644 mrblib/file.rb create mode 100644 mrblib/file_constants.rb create mode 100644 mrblib/io.rb create mode 100644 run_test.rb create mode 100644 src/file.c create mode 100644 src/file_test.c create mode 100644 src/io.c create mode 100644 src/mruby_io_gem.c create mode 100644 test/file.rb create mode 100644 test/file_test.rb create mode 100644 test/io.rb create mode 100644 test/mruby_io_test.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ceeb05b41 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/tmp diff --git a/README.md b/README.md new file mode 100644 index 000000000..01d29521a --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +mruby-io +======== + +under construction + diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h new file mode 100644 index 000000000..7ecf0a4a4 --- /dev/null +++ b/include/mruby/ext/io.h @@ -0,0 +1,60 @@ +/* +** io.h - IO class +*/ + +#ifndef MRUBY_IO_H +#define MRUBY_IO_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +struct mrb_io { + int fd; /* file descriptor */ + int fd2; /* file descriptor */ + int pid; /* child's pid (for pipes) */ +}; + +struct mrb_io_type { + const char *struct_name; + void (*dfree)(mrb_state *mrb, void *); +}; + +#define FMODE_READABLE 0x00000001 +#define FMODE_WRITABLE 0x00000002 +#define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE) +#define FMODE_BINMODE 0x00000004 +#define FMODE_SYNC 0x00000008 +#define FMODE_TTY 0x00000010 +#define FMODE_DUPLEX 0x00000020 +#define FMODE_APPEND 0x00000040 +#define FMODE_CREATE 0x00000080 +#define FMODE_WSPLIT 0x00000200 +#define FMODE_WSPLIT_INITIALIZED 0x00000400 +#define FMODE_TRUNC 0x00000800 +#define FMODE_TEXTMODE 0x00001000 +#define FMODE_SETENC_BY_BOM 0x00100000 + +#define E_IO_ERROR (mrb_class_obj_get(mrb, "IOError")) +#define E_EOF_ERROR (mrb_class_obj_get(mrb, "EOFError")) + +mrb_value mrb_open_file(mrb_state *mrb, int argc, mrb_value *argv, mrb_value io); +void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise); +mrb_value mrb_file_exist(mrb_state *mrb, mrb_value fname); + +#if defined(__cplusplus) +} /* extern "C" { */ +#endif +#endif /* MRUBY_IO_H */ diff --git a/mrbgem.rake b/mrbgem.rake new file mode 100644 index 000000000..10e192c45 --- /dev/null +++ b/mrbgem.rake @@ -0,0 +1,6 @@ +MRuby::Gem::Specification.new('mruby-io') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan' + + spec.cc.include_paths << "#{build.root}/src" +end diff --git a/mrblib/file.rb b/mrblib/file.rb new file mode 100644 index 000000000..566085066 --- /dev/null +++ b/mrblib/file.rb @@ -0,0 +1,108 @@ +class File < IO + include Enumerable + + class FileError < Exception; end + class NoFileError < FileError; end + class UnableToStat < FileError; end + class PermissionError < FileError; end + + attr_accessor :path + + def initialize(fd_or_path, mode = "r", perm = 0666) + self._bless + if fd_or_path.kind_of? Fixnum + super(fd_or_path, mode) + else + @path = fd_or_path + + perm = 0666 unless perm.is_a? Fixnum + fd = IO.sysopen(@path, mode, perm) + if fd < 0 && Object.const_defined?(:Errno) + begin + Errno.handle @path + rescue Errno::EMFILE + GC.run(true) + fd = IO.sysopen(@path, mode, perm) + Errno.handle if fd < 0 + end + elsif fd < 0 + raise NoFileError.new "no such file or directory" + end + super(fd, mode) + end + end + + def self.join(*names) + if names.size == 0 + "" + elsif names.size == 1 + names[0] + else + if names[0][-1] == File::SEPARATOR + s = names[0][0..-2] + else + s = names[0].dup + end + (1..names.size-2).each { |i| + t = names[i] + if t[0] == File::SEPARATOR and t[-1] == File::SEPARATOR + t = t[1..-2] + elsif t[0] == File::SEPARATOR + t = t[1..-1] + elsif t[-1] == File::SEPARATOR + t = t[0..-2] + end + s += File::SEPARATOR + t if t != "" + } + if names[-1][0] == File::SEPARATOR + s += File::SEPARATOR + names[-1][1..-1] + else + s += File::SEPARATOR + names[-1] + end + s + end + end + + def self.directory?(file) + FileTest.directory?(file) + end + + def self.exist?(file) + FileTest.exist?(file) + end + + def self.exists?(file) + FileTest.exists?(file) + end + + def self.file?(file) + FileTest.file?(file) + end + + def self.pipe?(file) + FileTest.pipe?(file) + end + + def self.size?(file) + FileTest.size?(file) + end + + def self.socket?(file) + FileTest.socket?(file) + end + + def self.symlink?(file) + FileTest.symlink?(file) + end + + def self.zero?(file) + FileTest.zero?(file) + end + + def self.extname(filename) + fname = self.basename(filename) + return '' if fname[0] == '.' || fname.index('.').nil? + ext = fname.split('.').last + ext.empty? ? '' : ".#{ext}" + end +end diff --git a/mrblib/file_constants.rb b/mrblib/file_constants.rb new file mode 100644 index 000000000..c2552bf56 --- /dev/null +++ b/mrblib/file_constants.rb @@ -0,0 +1,31 @@ +class File + module Constants + NULL = "/dev/null" + + RDONLY = 0 + WRONLY = 1 + RDWR = 2 + NONBLOCK = 4 + APPEND = 8 + + BINARY = 0 + SYNC = 128 + NOFOLLOW = 256 + CREAT = 512 + TRUNC = 1024 + EXCL = 2048 + + NOCTTY = 131072 + DSYNC = 4194304 + + FNM_SYSCASE = 0 + FNM_NOESCAPE = 1 + FNM_PATHNAME = 2 + FNM_DOTMATCH = 4 + FNM_CASEFOLD = 8 + end +end + +class File + include File::Constants +end diff --git a/mrblib/io.rb b/mrblib/io.rb new file mode 100644 index 000000000..3c679d3f7 --- /dev/null +++ b/mrblib/io.rb @@ -0,0 +1,271 @@ +## +# IO + +class IOError < StandardError; end +class EOFError < IOError; end + +class IO + SEEK_SET = 0 + SEEK_CUR = 1 + SEEK_END = 2 + + BUF_SIZE = 4096 + + def self.open(fd, mode = "r", opt = {}, &block) + io = self.new(fd, mode, opt) + + return io unless block + + begin + yield io + ensure + begin + io.close unless io.closed? + rescue StandardError + end + end + end + + def self.popen(command, mode = 'r', &block) + io = self._popen(command, mode) + return io unless block + + begin + yield io + ensure + begin + io.close unless io.closed? + rescue IOError + # nothing + end + end + end + + def write(string) + str = string.is_a?(String) ? string : string.to_s + return str.size unless str.size > 0 + + len = syswrite(str) + if str.size == len + @pos += len + return len + end + + raise IOError + end + + def eof? + # XXX: @buf のことを考えなくてよい?? + ret = false + char = '' + + begin + char = sysread(1) + rescue EOFError => e + ret = true + ensure + _ungets(char) + end + + ret + end + alias_method :eof, :eof? + + def pos + raise IOError if closed? + @pos + end + alias_method :tell, :pos + + def pos=(i) + seek(i, SEEK_SET) + end + + def seek(i, whence = SEEK_SET) + raise IOError if closed? + @pos = sysseek(i, whence) + @buf = '' + 0 + end + + def _read_buf + return @buf if @buf && @buf.size > 0 + @buf = sysread(BUF_SIZE) + end + + def _ungets(substr) + raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String) + raise IOError if @pos == 0 || @pos.nil? + @pos -= substr.size + if @buf.empty? + @buf = substr + else + @buf = substr + @buf + end + nil + end + + def ungetc(char) + raise IOError if @pos == 0 || @pos.nil? + _ungets(char) + nil + end + + def read(length = nil) + unless length.nil? or length.class == Fixnum + raise TypeError.new "can't convert #{length.class} into Integer" + end + if length && length < 0 + raise ArgumentError.new "negative length: #{length} given" + end + + str = '' + while 1 + begin + _read_buf + rescue EOFError => e + str = nil if str.empty? + break + end + + if length && (str.size + @buf.size) >= length + len = length - str.size + str += @buf[0, len] + @pos += len + @buf = @buf[len, @buf.size - len] + break + else + str += @buf + @pos += @buf.size + @buf = '' + end + end + + str + end + + def readline(arg = $/, limit = nil) + case arg + when String + rs = arg + when Fixnum + rs = $/ + limit = arg + else + raise ArgumentError + end + + if rs.nil? + return read + end + + if rs == "" + rs = $/ + $/ + end + + str = "" + while 1 + begin + _read_buf + rescue EOFError => e + str = nil if str.empty? + break + end + + if limit && (str.size + @buf.size) >= limit + len = limit - str.size + str += @buf[0, len] + @pos += len + @buf = @buf[len, @buf.size - len] + break + elsif idx = @buf.index(rs) + len = idx + rs.size + str += @buf[0, len] + @pos += len + @buf = @buf[len, @buf.size - len] + break + else + str += @buf + @pos += @buf.size + @buf = '' + end + end + + raise EOFError.new "end of file reached" if str.nil? + + str + end + + def gets(*args) + begin + readline(*args) + rescue EOFError => e + nil + end + end + + def readchar + _read_buf + c = @buf[0] + @buf = @buf[1, @buf.size] + @pos += 1 + c + end + + def getc + begin + readchar + rescue EOFError => e + nil + end + end + + # 15.2.20.5.3 + def each(&block) + while line = self.gets + block.call(line) + end + self + end + + # 15.2.20.5.4 + def each_byte(&block) + while char = self.getc + block.call(char) + end + self + end + + # 15.2.20.5.5 + alias each_line each + + alias each_char each_byte + + def readlines + ary = [] + while (line = gets) + ary << line + end + ary + end + + def puts(*args) + i = 0 + len = args.size + while i < len + s = args[i].to_s + write s + write "\n" if (s[-1] != "\n") + i += 1 + end + write "\n" if len == 0 + nil + end + + def printf(*args) + write sprintf(*args) + nil + end + + alias_method :to_i, :fileno +end diff --git a/run_test.rb b/run_test.rb new file mode 100644 index 000000000..e83b504be --- /dev/null +++ b/run_test.rb @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +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 + 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 "#{root}/mrbgems/mruby-sprintf" + conf.gem "#{root}/mrbgems/mruby-print" + + Dir.glob("#{root}/mrbgems/mruby-*") do |x| + conf.gem x unless x =~ /\/mruby-(print|sprintf)$/ + end + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/src/file.c b/src/file.c new file mode 100644 index 000000000..fe6965943 --- /dev/null +++ b/src/file.c @@ -0,0 +1,294 @@ +/* +** file.c - File class +*/ + +#include "mruby.h" + +#include "mruby/ext/io.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include "error.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FILE_SEPARATOR "/" + +#ifndef LOCK_SH +#define LOCK_SH 1 +#endif +#ifndef LOCK_EX +#define LOCK_EX 2 +#endif +#ifndef LOCK_NB +#define LOCK_NB 4 +#endif +#ifndef LOCK_UN +#define LOCK_UN 8 +#endif + +#define STAT(p, s) stat(p, s) + +mrb_value +mrb_file_s_umask(mrb_state *mrb, mrb_value klass) +{ + mrb_value *argv; + int argc; + mrb_get_args(mrb, "*", &argv, &argc); + + int omask = 0; + if (argc == 0) { + omask = umask(0); + umask(omask); + } else if (argc == 1) { + mrb_value mask = argv[0]; + if (!mrb_nil_p(mask) && !mrb_fixnum_p(mask)) { + mask = mrb_check_convert_type(mrb, mask, MRB_TT_FIXNUM, "Fixnum", "to_int"); + } + if (!mrb_fixnum_p(mask)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type"); + } + omask = umask(mrb_fixnum(mask)); + } else { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 0..1)", argc); + } + return mrb_fixnum_value(omask); +} + +static mrb_value +mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) +{ + mrb_value *argv; + int n, i, argc; + + mrb_get_args(mrb, "*", &argv, &argc); + for (i = 0, n = 0; i < argc; i++) { + mrb_value pathv = argv[i]; + if (mrb_type(pathv) != MRB_TT_STRING) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, pathv)); + } + const char *path = mrb_string_value_cstr(mrb, &pathv);; + if (unlink(path) < 0) { + mrb_sys_fail(mrb, path); + } else { + n++; + } + } + return mrb_fixnum_value(n); +} + +static mrb_value +mrb_file_rename_internal(mrb_state *mrb, mrb_value from, mrb_value to) +{ + const char *src, *dst; + src = mrb_string_value_cstr(mrb, &from); + dst = mrb_string_value_cstr(mrb, &to); + + if (rename(src, dst) < 0) { + if (chmod(dst, 0666) == 0 && + unlink(dst) == 0 && + rename(src, dst) == 0) + return mrb_fixnum_value(0); + mrb_sys_fail(mrb, "mrb_file_rename_internal failed."); + } + + return mrb_fixnum_value(0); +} + +static mrb_value +mrb_file_s_rename(mrb_state *mrb, mrb_value obj) +{ + mrb_value *argv; + int argc; + + mrb_get_args(mrb, "*", &argv, &argc); + if (argc != 2) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 2)", argc); + return mrb_nil_value(); + } + if (mrb_type(argv[0]) != MRB_TT_STRING) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, argv[0])); + return mrb_nil_value(); + } + if (mrb_type(argv[1]) != MRB_TT_STRING) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, argv[1])); + return mrb_nil_value(); + } + + return mrb_file_rename_internal(mrb, argv[0], argv[1]); +} + + +static mrb_value +mrb_file_dirname(mrb_state *mrb, mrb_value klass) +{ + char *cp, *dname; + mrb_int n; + mrb_value fname; + + mrb_get_args(mrb, "s", &cp, &n); + fname = mrb_str_new(mrb, cp, n); + + if ((dname = dirname(RSTRING_PTR(fname))) == NULL) { + mrb_sys_fail(mrb, "mrb_file_dirname failed."); + } + + return mrb_str_new(mrb, dname, strlen(dname)); +} + +static mrb_value +mrb_file_basename(mrb_state *mrb, mrb_value klass) +{ + char *cp, *bname; + mrb_int n; + mrb_value fname; + + mrb_get_args(mrb, "s", &cp, &n); + fname = mrb_str_new(mrb, cp, n); + + if ((bname = basename(RSTRING_PTR(fname))) == NULL) { + mrb_sys_fail(mrb, "mrb_file_basename failed."); + } + + return mrb_str_new(mrb, bname, strlen(bname)); +} + +static mrb_value +mrb_file_realpath(mrb_state *mrb, mrb_value klass) +{ + mrb_value pathname, dir_string, s, result; + int argc; + char *cpath; + + argc = mrb_get_args(mrb, "S|S", &pathname, &dir_string); + if (argc == 2) { + s = mrb_str_dup(mrb, dir_string); + s = mrb_str_append(mrb, s, mrb_str_new_cstr(mrb, FILE_SEPARATOR)); + s = mrb_str_append(mrb, s, pathname); + pathname = s; + } + cpath = mrb_str_to_cstr(mrb, pathname); + result = mrb_str_buf_new(mrb, PATH_MAX); + if (realpath(cpath, RSTRING_PTR(result)) == NULL) + mrb_sys_fail(mrb, cpath); + mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result))); + return result; +} + +static mrb_value +mrb_file_size(mrb_state *mrb, mrb_value klass) +{ + char *cp; + FILE *fp; + mrb_int n; + mrb_int filesize; + mrb_value filename; + + mrb_get_args(mrb, "s", &cp, &n); + filename = mrb_str_new(mrb, cp, n); + + fp = fopen(RSTRING_PTR(filename), "rb"); + if (fp == NULL) { + mrb_sys_fail(mrb, "mrb_file_size failed."); + return mrb_nil_value(); + } + + fseek(fp, 0, SEEK_END); + filesize = (mrb_int) ftell(fp); + + fclose(fp); + + return mrb_fixnum_value(filesize); +} + +mrb_value +mrb_file__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; +} + +static int +mrb_file_is_absolute_path(const char *path) +{ + if (path[0] == '/') + return 1; + return 0; +} + +static mrb_value +mrb_file__gethome(mrb_state *mrb, mrb_value klass) +{ + mrb_value username, result; + char *cuser, *home; + int argc; + struct passwd *pwd; + + argc = mrb_get_args(mrb, "|S", &username); + + if (argc == 0) { + home = getenv("HOME"); + } else { + cuser = mrb_str_to_cstr(mrb, username); + if ((pwd = getpwnam(cuser)) == NULL) { + return mrb_nil_value(); + } else { + home = pwd->pw_dir; + } + } + + if (!mrb_file_is_absolute_path(home)) { + if (argc && strlen(cuser) > 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%s", cuser); + } else { + mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home"); + } + } + + result = mrb_str_buf_new(mrb, strlen(home)); + strcpy( RSTRING_PTR(result), home); + mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result))); + + return result; +} + +void +mrb_init_file(mrb_state *mrb) +{ + struct RClass *io, *file, *cnst; + + io = mrb_class_obj_get(mrb, "IO"); + file = mrb_define_class(mrb, "File", io); + MRB_SET_INSTANCE_TT(file, MRB_TT_DATA); + mrb_define_class_method(mrb, file, "umask", mrb_file_s_umask, ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, ARGS_ANY()); + mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, ARGS_ANY()); + mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, ARGS_REQ(2)); + + mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "basename", mrb_file_basename, ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "realpath", mrb_file_realpath, ARGS_REQ(1)|ARGS_OPT(1)); + mrb_define_class_method(mrb, file, "size", mrb_file_size, ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, ARGS_NONE()); + mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, ARGS_OPT(1)); + + cnst = mrb_define_module_under(mrb, file, "Constants"); + mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH)); + mrb_define_const(mrb, cnst, "LOCK_EX", mrb_fixnum_value(LOCK_EX)); + mrb_define_const(mrb, cnst, "LOCK_UN", mrb_fixnum_value(LOCK_UN)); + mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB)); + mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR)); +} diff --git a/src/file_test.c b/src/file_test.c new file mode 100644 index 000000000..dcc6a2fd4 --- /dev/null +++ b/src/file_test.c @@ -0,0 +1,307 @@ +/* +** file.c - File class +*/ + +#include "mruby.h" + +#include "mruby/ext/io.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include "error.h" + +#include +#include +#include +#include +#include +#include +#include + +extern struct mrb_data_type mrb_io_type; + +static int +mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st) +{ + mrb_value tmp; + mrb_value io_klass, str_klass; + + io_klass = mrb_obj_value(mrb_class_obj_get(mrb, "IO")); + str_klass = mrb_obj_value(mrb_class_obj_get(mrb, "String")); + + tmp = mrb_funcall(mrb, obj, "is_a?", 1, io_klass); + if (mrb_test(tmp)) { + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type); + + if (fptr && fptr->fd >= 0) { + return fstat(fptr->fd, st); + } + + mrb_raise(mrb, E_IO_ERROR, "closed stream"); + return -1; + } + + tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); + if (mrb_test(tmp)) { + return stat(mrb_string_value_cstr(mrb, &obj), st); + } + + return -1; +} + +/* + * Document-method: directory? + * + * call-seq: + * File.directory?(file_name) -> true or false + * + * Returns true if the named file is a directory, + * or a symlink that points at a directory, and false + * otherwise. + * + * File.directory?(".") + */ + +mrb_value +mrb_filetest_s_directory_p(mrb_state *mrb, mrb_value klass) +{ +#ifndef S_ISDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (S_ISDIR(st.st_mode)) + return mrb_true_value(); + + return mrb_false_value(); +} + +/* + * call-seq: + * File.pipe?(file_name) -> true or false + * + * Returns true if the named file is a pipe. + */ + +mrb_value +mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass) +{ +#ifdef S_IFIFO +# ifndef S_ISFIFO +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# endif + + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (S_ISFIFO(st.st_mode)) + return mrb_true_value(); + +#endif + return mrb_false_value(); +} + +/* + * call-seq: + * File.symlink?(file_name) -> true or false + * + * Returns true if the named file is a symbolic link. + */ + +mrb_value +mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass) +{ +#ifndef S_ISLNK +# ifdef _S_ISLNK +# define S_ISLNK(m) _S_ISLNK(m) +# else +# ifdef _S_IFLNK +# define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK) +# else +# ifdef S_IFLNK +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# endif +# endif +# endif +#endif + +#ifdef S_ISLNK + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (S_ISLNK(st.st_mode)) + return mrb_true_value(); +#endif + + return mrb_false_value(); +} + +/* + * call-seq: + * File.socket?(file_name) -> true or false + * + * Returns true if the named file is a socket. + */ + +mrb_value +mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass) +{ +#ifndef S_ISSOCK +# ifdef _S_ISSOCK +# define S_ISSOCK(m) _S_ISSOCK(m) +# else +# ifdef _S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK) +# else +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# endif +# endif +# endif +#endif + +#ifdef S_ISSOCK + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (S_ISSOCK(st.st_mode)) + return mrb_true_value(); +#endif + + return mrb_false_value(); +} + +/* + * call-seq: + * File.exist?(file_name) -> true or false + * File.exists?(file_name) -> true or false + * + * Return true if the named file exists. + */ + +mrb_value +mrb_filetest_s_exist_p(mrb_state *mrb, mrb_value klass) +{ + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + + return mrb_true_value(); +} + +/* + * call-seq: + * File.file?(file_name) -> true or false + * + * Returns true if the named file exists and is a + * regular file. + */ + +mrb_value +mrb_filetest_s_file_p(mrb_state *mrb, mrb_value klass) +{ +#ifndef S_ISREG +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (S_ISREG(st.st_mode)) + return mrb_true_value(); + + return mrb_false_value(); +} + +/* + * call-seq: + * File.zero?(file_name) -> true or false + * + * Returns true if the named file exists and has + * a zero size. + */ + +mrb_value +mrb_filetest_s_zero_p(mrb_state *mrb, mrb_value klass) +{ + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_false_value(); + if (st.st_size == 0) + return mrb_true_value(); + + return mrb_false_value(); +} + +/* + * call-seq: + * File.size?(file_name) -> Integer or nil + * + * Returns +nil+ if +file_name+ doesn't exist or has zero size, the size of the + * file otherwise. + */ + +mrb_value +mrb_filetest_s_size_p(mrb_state *mrb, mrb_value klass) +{ + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + return mrb_nil_value(); + if (st.st_size == 0) + return mrb_nil_value(); + + return mrb_fixnum_value(st.st_size); +} + + +void +mrb_init_file_test(mrb_state *mrb) +{ + struct RClass *f; + + f = mrb_define_class(mrb, "FileTest", mrb->object_class); + + mrb_define_class_method(mrb, f, "directory?", mrb_filetest_s_directory_p, ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "exist?", mrb_filetest_s_exist_p, ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "exists?", mrb_filetest_s_exist_p, ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "file?", mrb_filetest_s_file_p, ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "pipe?", mrb_filetest_s_pipe_p, ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "size?", mrb_filetest_s_size_p, ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "socket?", mrb_filetest_s_socket_p, ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "symlink?", mrb_filetest_s_symlink_p, ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "zero?", mrb_filetest_s_zero_p, ARGS_REQ(1)); +} diff --git a/src/io.c b/src/io.c new file mode 100644 index 000000000..e5fe6a73f --- /dev/null +++ b/src/io.c @@ -0,0 +1,755 @@ +/* +** io.c - IO class +*/ + +#include "mruby.h" + +#include "mruby/hash.h" +#include "mruby/data.h" +#include "mruby/khash.h" +#include "mruby/array.h" +#include "mruby/class.h" +#include "mruby/string.h" +#include "mruby/variable.h" +#include "mruby/ext/io.h" +#include "error.h" + +static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr); +static int mrb_io_modenum_to_flags(mrb_state *mrb, int modenum); +static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags); + +static int +mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) +{ + int flags = 0; + const char *m = mode; + + switch (*m++) { + case 'r': + flags |= FMODE_READABLE; + break; + case 'w': + flags |= FMODE_WRITABLE | FMODE_CREATE; + break; + case 'a': + flags |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE; + break; + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %s", mode); + } + + while (*m) { + switch (*m++) { + case 'b': + flags |= FMODE_BINMODE; + break; + case '+': + flags |= FMODE_READWRITE; + break; + case ':': + /* XXX: PASSTHROUGH*/ + default: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %s", mode); + } + } + + return flags; +} + +static int +mrb_io_modenum_to_flags(mrb_state *mrb, int modenum) +{ + int flags = 0; + + switch (modenum & (O_RDONLY|O_WRONLY|O_RDWR)) { + case O_RDONLY: + flags = FMODE_READABLE; + break; + case O_WRONLY: + flags = FMODE_WRITABLE; + break; + case O_RDWR: + flags = FMODE_READWRITE; + break; + } + + if (modenum & O_APPEND) { + flags |= FMODE_APPEND; + } + if (modenum & O_TRUNC) { + flags |= FMODE_TRUNC; + } + if (modenum & O_CREAT) { + flags |= FMODE_CREATE; + } +#ifdef O_BINARY + if (modenum & O_BINARY) { + flags |= FMODE_BINMODE; + } +#endif + + return flags; +} + +static int +mrb_io_flags_to_modenum(mrb_state *mrb, int flags) +{ + int modenum = 0; + + switch(flags & (FMODE_READABLE|FMODE_WRITABLE|FMODE_READWRITE)) { + case FMODE_READABLE: + modenum = O_RDONLY; + break; + case FMODE_WRITABLE: + modenum = O_WRONLY; + break; + case FMODE_READWRITE: + modenum = O_RDWR; + break; + } + + if (flags & FMODE_APPEND) { + modenum |= O_APPEND; + } + if (flags & FMODE_TRUNC) { + modenum |= O_TRUNC; + } + if (flags & FMODE_CREATE) { + modenum |= O_CREAT; + } +#ifdef O_BINARY + if (flags & FMODE_BINMODE) { + modenum |= O_BINARY + } +#endif + + return modenum; +} + +static int +mrb_proc_exec(const char *pname) +{ + const char *s; + s = pname; + + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + + if (!*s) { + errno = ENOENT; + return -1; + } + + execl("/bin/sh", "sh", "-c", pname, (char *)NULL); + return -1; +} + +static void +mrb_io_free(mrb_state *mrb, void *ptr) +{ + struct mrb_io *io = (struct mrb_io *)ptr; + if (io != NULL) { + fptr_finalize(mrb, io, TRUE); + mrb_free(mrb, io); + } +} + +struct mrb_data_type mrb_io_type = { "IO", mrb_io_free }; + +static struct mrb_io* +mrb_io_alloc(mrb_state *mrb) +{ + struct mrb_io *fptr; + + fptr = (struct mrb_io *)mrb_malloc(mrb, sizeof(struct mrb_io)); + fptr->fd = -1; + fptr->fd2 = -1; + fptr->pid = 0; + + return fptr; +} + +static int +io_open(mrb_state *mrb, mrb_value path, int flags, int perm) +{ + const char *pat; + int modenum; + + pat = mrb_string_value_cstr(mrb, &path); + modenum = mrb_io_flags_to_modenum(mrb, flags); + + return open(pat, modenum, perm); +} + +#ifndef NOFILE +#define NOFILE 64 +#endif + +mrb_value +mrb_io_s_popen(mrb_state *mrb, mrb_value klass) +{ + mrb_value cmd, io; + mrb_value mode = mrb_str_new_cstr(mrb, "r"); + mrb_value opt = mrb_hash_new(mrb); + + struct mrb_io *fptr; + const char *pname; + int pid, flags, fd, write_fd = -1; + int pr[2], pw[2]; + int doexec; + + mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); + io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + + pname = mrb_string_value_cstr(mrb, &cmd); + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + + doexec = (strcmp("-", pname) != 0); + + if (((flags & FMODE_READABLE) && pipe(pr) == -1) + || ((flags & FMODE_WRITABLE) && pipe(pw) == -1)) { + mrb_sys_fail(mrb, "pipe_open failed."); + return mrb_nil_value(); + } + + if (!doexec) { + // XXX + fflush(stdin); + fflush(stdout); + fflush(stderr); + } + +retry: + switch (pid = fork()) { + case 0: /* child */ + if (flags & FMODE_READABLE) { + close(pr[0]); + if (pr[1] != 1) { + dup2(pr[1], 1); + close(pr[1]); + } + } + if (flags & FMODE_WRITABLE) { + close(pw[1]); + if (pw[0] != 0) { + dup2(pw[0], 0); + close(pw[0]); + } + } + + if (doexec) { + for (fd = 3; fd < NOFILE; fd++) { + close(fd); + } + mrb_proc_exec(pname); + mrb_raisef(mrb, E_IO_ERROR, "command not found: %s", pname); + _exit(127); + } + return mrb_nil_value(); + case -1: /* error */ + if (errno == EAGAIN) { + goto retry; + } else { + int e = errno; + if (flags & FMODE_READABLE) { + close(pr[0]); + close(pr[1]); + } + if (flags & FMODE_WRITABLE) { + close(pw[0]); + close(pw[1]); + } + + errno = e; + mrb_sys_fail(mrb, "pipe_open failed."); + } + break; + default: /* parent */ + if (pid < 0) { + mrb_sys_fail(mrb, "pipe_open failed."); + return mrb_nil_value(); + } else { + if ((flags & FMODE_READABLE) && (flags & FMODE_WRITABLE)) { + close(pr[1]); + fd = pr[0]; + close(pw[0]); + write_fd = pw[1]; + } else if (flags & FMODE_READABLE) { + close(pr[1]); + fd = pr[0]; + } else { + close(pw[0]); + fd = pw[1]; + } + + mrb_iv_set(mrb, io, mrb_intern(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, io, mrb_intern(mrb, "@pos"), mrb_fixnum_value(0)); + + fptr = mrb_io_alloc(mrb); + fptr->fd = fd; + fptr->fd2 = write_fd; + fptr->pid = pid; + + DATA_TYPE(io) = &mrb_io_type; + DATA_PTR(io) = fptr; + return io; + } + } + + return mrb_nil_value(); +} + +mrb_value +mrb_io_initialize(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + mrb_int fd, flags; + mrb_value mode, opt; + + DATA_TYPE(io) = &mrb_io_type; + DATA_PTR(io) = NULL; + + mode = opt = mrb_nil_value(); + + mrb_get_args(mrb, "i|So", &fd, &mode, &opt); + if (mrb_nil_p(mode)) { + mode = mrb_str_new_cstr(mrb, "r"); + } + if (mrb_nil_p(opt)) { + opt = mrb_hash_new(mrb); + } + + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + + mrb_iv_set(mrb, io, mrb_intern(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, io, mrb_intern(mrb, "@pos"), mrb_fixnum_value(0)); + + fptr = DATA_PTR(io); + if (fptr == NULL) { + fptr = mrb_io_alloc(mrb); + } + fptr->fd = fd; + + DATA_PTR(io) = fptr; + + return io; +} + +void +fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) +{ + int n = 0; + + if (fptr == NULL) { + return; + } + + if (fptr->fd > 2) { + n = close(fptr->fd); + if (n == 0) { + fptr->fd = -1; + } + } + if (fptr->fd2 > 2) { + n = close(fptr->fd2); + if (n == 0) { + fptr->fd2 = -1; + } + } + + if (!noraise && n != 0) { + mrb_sys_fail(mrb, "fptr_finalize failed."); + } +} + +mrb_value +mrb_io_bless(mrb_state *mrb, mrb_value io) +{ + if (mrb_type(io) != MRB_TT_DATA) { + mrb_raise(mrb, E_TYPE_ERROR, "expected IO object"); + return mrb_nil_value(); + } + + DATA_TYPE(io) = &mrb_io_type; + DATA_PTR(io) = NULL; + DATA_PTR(io) = mrb_io_alloc(mrb); + + return io; +} + +mrb_value +mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass) +{ + mrb_value io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + + return mrb_io_initialize(mrb, io); +} + +mrb_value +mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) +{ + mrb_value path = mrb_nil_value(); + mrb_value mode = mrb_nil_value(); + mrb_int fd, flags, perm = -1; + + mrb_get_args(mrb, "S|Si", &path, &mode, &perm); + if (mrb_nil_p(mode)) { + mode = mrb_str_new_cstr(mrb, "r"); + } + if (perm < 0) { + perm = 0666; + } + + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + fd = io_open(mrb, path, flags, perm); + + return mrb_fixnum_value(fd); +} + +mrb_value +mrb_io_sysread(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + mrb_value buf = mrb_nil_value(); + int maxlen, ret; + + mrb_get_args(mrb, "i|S", &maxlen, &buf); + if (maxlen < 0) { + return mrb_nil_value(); + } + + if (mrb_nil_p(buf)) { + buf = mrb_str_new(mrb, "", maxlen); + } + if (RSTRING_LEN(buf) != maxlen) { + buf = mrb_str_resize(mrb, buf, maxlen); + } + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + ret = read(fptr->fd, RSTRING_PTR(buf), maxlen); + switch (ret) { + case 0: /* EOF */ + if (maxlen == 0) { + buf = mrb_str_new_cstr(mrb, ""); + } else { + mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File"); + return mrb_nil_value(); + } + break; + case -1: /* Error */ + mrb_raise(mrb, E_IO_ERROR, "sysread failed"); + return mrb_nil_value(); + break; + default: + if (RSTRING_LEN(buf) != ret) { + buf = mrb_str_resize(mrb, buf, ret); + } + break; + } + + return buf; +} + +mrb_value +mrb_io_sysseek(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + int pos, offset, whence = -1; + + mrb_get_args(mrb, "i|i", &offset, &whence); + if (whence < 0) { + whence = 0; + } + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + pos = lseek(fptr->fd, offset, whence); + if (pos < 0) { + mrb_raise(mrb, E_IO_ERROR, "sysseek faield"); + return mrb_nil_value(); + } + + return mrb_fixnum_value(pos); +} + +mrb_value +mrb_io_syswrite(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + mrb_value str, buf; + int length; + + mrb_get_args(mrb, "S", &str); + if (mrb_type(str) != MRB_TT_STRING) { + buf = mrb_funcall(mrb, str, "to_s", 0); + } else { + buf = str; + } + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + length = write(fptr->fd, RSTRING_PTR(buf), RSTRING_LEN(buf)); + + return mrb_fixnum_value(length); +} + +mrb_value +mrb_io_close(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + if (fptr && fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream."); + return mrb_nil_value(); + } + + fptr_finalize(mrb, fptr, FALSE); + return mrb_nil_value(); +} + +mrb_value +mrb_io_closed(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + + if (fptr->fd >= 0) { + return mrb_false_value(); + } + + return mrb_true_value(); +} + +mrb_value +mrb_io_pid(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + + if (fptr->pid > 0) { + return mrb_fixnum_value(fptr->pid); + } + + return mrb_nil_value(); +} + +static struct timeval +time2timeval(mrb_state *mrb, mrb_value time) +{ + struct timeval t; + + switch (mrb_type(time)) { + case MRB_TT_FIXNUM: + t.tv_sec = mrb_fixnum(time); + t.tv_usec = 0; + break; + + case MRB_TT_FLOAT: + t.tv_sec = mrb_float(time); + t.tv_usec = (mrb_float(time) - t.tv_sec) * 1000000.0; + break; + + default: + mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); + } + + return t; +} + +static mrb_value +mrb_io_select(mrb_state *mrb, mrb_value klass) +{ + mrb_value *argv; + int argc; + mrb_value read, write, except, timeout, list; + struct timeval *tp, timerec; + fd_set pset, rset, wset, eset; + fd_set *rp, *wp, *ep; + struct mrb_io *fptr; + int pending = 0; + mrb_value result; + int max = 0; + int interrupt_flag = 0; + int i, n; + + mrb_get_args(mrb, "*", &argv, &argc); + + if (argc < 1 || argc > 4) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, + "wrong number of arguments (%d for 1..4)", argc); + return mrb_nil_value(); + } + + timeout = mrb_nil_value(); + except = mrb_nil_value(); + write = mrb_nil_value(); + if (argc > 3) + timeout = argv[3]; + if (argc > 2) + except = argv[2]; + if (argc > 1) + write = argv[1]; + read = argv[0]; + + if (mrb_nil_p(timeout)) { + tp = NULL; + } else { + timerec = time2timeval(mrb, timeout); + tp = &timerec; + } + + FD_ZERO(&pset); + if (!mrb_nil_p(read)) { + mrb_check_type(mrb, read, MRB_TT_ARRAY); + rp = &rset; + FD_ZERO(rp); + for (i = 0; i < RARRAY_LEN(read); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(read)[i], &mrb_io_type); + FD_SET(fptr->fd, rp); + /* XXX: ..... + if (READ_DATA_PENDING(fptr->f)) { + pending++; + FD_SET(fileno(fptr->f), &pset); + } + */ + if (max < fptr->fd) + max = fptr->fd; + } + if (pending) { + timerec.tv_sec = timerec.tv_usec = 0; + tp = &timerec; + } + } else { + rp = NULL; + } + + if (!mrb_nil_p(write)) { + mrb_check_type(mrb, write, MRB_TT_ARRAY); + wp = &wset; + FD_ZERO(wp); + for (i = 0; i < RARRAY_LEN(write); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(write)[i], &mrb_io_type); + FD_SET(fptr->fd, wp); + if (max < fptr->fd) + max = fptr->fd; + if (fptr->fd2 >= 0) { + FD_SET(fptr->fd2, wp); + if (max < fptr->fd2) + max = fptr->fd2; + } + } + } else { + wp = NULL; + } + + if (!mrb_nil_p(except)) { + mrb_check_type(mrb, except, MRB_TT_ARRAY); + ep = &eset; + FD_ZERO(ep); + for (i = 0; i < RARRAY_LEN(except); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type); + FD_SET(fptr->fd, ep); + if (max < fptr->fd) + max = fptr->fd; + if (fptr->fd2) { + FD_SET(fptr->fd2, ep); + if (max < fptr->fd2) + max = fptr->fd2; + } + } + } else { + ep = NULL; + } + + max++; + +retry: + n = select(max, rp, wp, ep, tp); + if (n < 0) { + if (errno != EINTR) + mrb_sys_fail(mrb, "select failed"); + if (tp == NULL) + goto retry; + interrupt_flag = 1; + } + + if (!pending && n == 0) + return mrb_nil_value(); + + result = mrb_ary_new_capa(mrb, 3); + mrb_ary_push(mrb, result, rp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0)); + mrb_ary_push(mrb, result, wp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0)); + mrb_ary_push(mrb, result, ep? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0)); + + if (interrupt_flag == 0) { + if (rp) { + list = RARRAY_PTR(result)[0]; + for (i = 0; i < RARRAY_LEN(read); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(read)[i], &mrb_io_type); + if (FD_ISSET(fptr->fd, rp) || + FD_ISSET(fptr->fd, &pset)) { + mrb_ary_push(mrb, list, RARRAY_PTR(read)[i]); + } + } + } + + if (wp) { + list = RARRAY_PTR(result)[1]; + for (i = 0; i < RARRAY_LEN(write); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(write)[i], &mrb_io_type); + if (FD_ISSET(fptr->fd, wp)) { + mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]); + } else if (fptr->fd2 && FD_ISSET(fptr->fd2, wp)) { + mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]); + } + } + } + + if (ep) { + list = RARRAY_PTR(result)[2]; + for (i = 0; i < RARRAY_LEN(except); i++) { + fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type); + if (FD_ISSET(fptr->fd, ep)) { + mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]); + } else if (fptr->fd2 && FD_ISSET(fptr->fd2, wp)) { + mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]); + } + } + } + } + + return result; +} + +mrb_value +mrb_io_fileno(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + return mrb_fixnum_value(fptr->fd); +} + +void +mrb_init_io(mrb_state *mrb) +{ + struct RClass *io; + + io = mrb_define_class(mrb, "IO", mrb->object_class); + MRB_SET_INSTANCE_TT(io, MRB_TT_DATA); + + mrb_include_module(mrb, io, mrb_class_get(mrb, "Enumerable")); /* 15.2.20.3 */ + + mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, ARGS_ANY()); + mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, ARGS_REQ(1)|ARGS_OPT(2)); + mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, ARGS_ANY()); + + mrb_define_method(mrb, io, "_bless", mrb_io_bless, ARGS_NONE()); + mrb_define_method(mrb, io, "initialize", mrb_io_initialize, ARGS_ANY()); /* 15.2.20.5.21 (x)*/ + mrb_define_method(mrb, io, "sysread", mrb_io_sysread, ARGS_ANY()); + mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, ARGS_REQ(1)); + mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, ARGS_REQ(1)); + mrb_define_method(mrb, io, "close", mrb_io_close, ARGS_NONE()); /* 15.2.20.5.1 */ + mrb_define_method(mrb, io, "closed?", mrb_io_closed, ARGS_NONE()); /* 15.2.20.5.2 */ + mrb_define_method(mrb, io, "pid", mrb_io_pid, ARGS_NONE()); /* 15.2.20.5.2 */ + mrb_define_method(mrb, io, "fileno", mrb_io_fileno, ARGS_NONE()); + + mrb_gv_set(mrb, mrb_intern(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); +} diff --git a/src/mruby_io_gem.c b/src/mruby_io_gem.c new file mode 100644 index 000000000..6880e6678 --- /dev/null +++ b/src/mruby_io_gem.c @@ -0,0 +1,20 @@ +#include "mruby.h" + +void mrb_init_io(mrb_state *mrb); +void mrb_init_file(mrb_state *mrb); +void mrb_init_file_test(mrb_state *mrb); + +#define DONE mrb_gc_arena_restore(mrb, 0) + +void +mrb_mruby_io_gem_init(mrb_state* mrb) +{ + mrb_init_io(mrb); DONE; + mrb_init_file(mrb); DONE; + mrb_init_file_test(mrb); DONE; +} + +void +mrb_mruby_io_gem_final(mrb_state* mrb) +{ +} diff --git a/test/file.rb b/test/file.rb new file mode 100644 index 000000000..f1bef32e5 --- /dev/null +++ b/test/file.rb @@ -0,0 +1,75 @@ +## +# IO Test + +assert('File', '15.2.21') do + File.class == Class +end + +assert('File', '15.2.21.2') do + File.superclass == IO +end + +assert('File TEST SETUP') do + MRubyIOTestUtil.io_test_setup +end + +assert('File#initialize', '15.2.21.4.1') do + io = File.open($mrbtest_io_rfname, "r") + assert_nil io.close + assert_raise IOError do + io.close + end +end + +assert('File#path', '15.2.21.4.2') do + io = File.open($mrbtest_io_rfname, "r") + assert_equal $mrbtest_io_msg + "\n", io.read + assert_equal $mrbtest_io_rfname, io.path + io.close + assert_equal $mrbtest_io_rfname, io.path + io.closed? +end + +assert('File.dirname') do + path = File.dirname("filename") + "." == path +end + +assert('File.basename') do + name = File.basename("../somewhere/filename") + name == "filename" +end + +assert('File.extname') do + assert_equal '.txt', File.extname('foo/foo.txt') + assert_equal '.gz', File.extname('foo/foo.tar.gz') + assert_equal '', File.extname('foo/bar') + assert_equal '', File.extname('foo/.bar') + assert_equal '', File.extname('foo.txt/bar') + assert_equal '', File.extname('.foo') +end + +assert('File.size') do + File.size($mrbtest_io_rfname) == $mrbtest_io_msg.size + 1 and + File.size($mrbtest_io_wfname) == 0 +end + +assert('File.join') do + File.join() == "" and + File.join("a") == "a" and + File.join("/a") == "/a" and + File.join("a/") == "a/" and + File.join("a", "b", "c") == "a/b/c" and + File.join("/a", "b", "c") == "/a/b/c" and + File.join("a", "b", "c/") == "a/b/c/" and + File.join("a/", "/b/", "/c") == "a/b/c" +end + +assert('File.realpath') do + usrbin = IO.popen("cd bin; /bin/pwd -P") { |f| f.read.chomp } + assert_equal usrbin, File.realpath("bin") +end + +assert('File TEST CLEANUP') do + assert_nil MRubyIOTestUtil.io_test_cleanup +end diff --git a/test/file_test.rb b/test/file_test.rb new file mode 100644 index 000000000..296679a6b --- /dev/null +++ b/test/file_test.rb @@ -0,0 +1,90 @@ +## +# FileTest + +assert('FileTest TEST SETUP') do + MRubyIOTestUtil.io_test_setup +end + +assert("FileTest.directory?") do + assert_equal true, FileTest.directory?("/tmp") + assert_equal false, FileTest.directory?("/bin/sh") +end + +assert("FileTest.exist?") do + assert_equal true, FileTest.exist?($mrbtest_io_rfname), "filename - exist" + assert_equal false, FileTest.exist?($mrbtest_io_rfname + "-"), "filename - not exist" + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + assert_equal true, FileTest.exist?(io), "io obj - exist" + io.close + assert_equal true, io.closed? + assert_raise IOError do + FileTest.exist?(io) + end +end + +assert("FileTest.file?") do + assert_equal false, FileTest.file?("/tmp") + assert_equal true, FileTest.file?("/bin/sh") +end + +assert("FileTest.pipe?") do + io = IO.popen("ls") + assert_equal true, FileTest.pipe?(io) + assert_equal false, FileTest.pipe?("/tmp") +end + +assert("FileTest.size?") do + assert_equal $mrbtest_io_msg.size+1, FileTest.size?($mrbtest_io_rfname) + assert_equal nil, FileTest.size?($mrbtest_io_wfname) + assert_equal nil, FileTest.size?("not-exist-test-target-file") + + fp1 = File.open($mrbtest_io_rfname) + fp2 = File.open($mrbtest_io_wfname) + assert_equal $mrbtest_io_msg.size+1, FileTest.size?(fp1) + assert_equal nil, FileTest.size?(fp2) + fp1.close + fp2.close + + assert_raise IOError do + FileTest.size?(fp1) + end + assert_raise IOError do + FileTest.size?(fp2) + end + + fp1.closed? && fp2.closed? +end + +assert("FileTest.socket?") do + skip +end + +assert("FileTest.symlink?") do + skip +end + +assert("FileTest.zero?") do + assert_equal false, FileTest.zero?($mrbtest_io_rfname) + assert_equal true, FileTest.zero?($mrbtest_io_wfname) + assert_equal false, FileTest.zero?("not-exist-test-target-file") + + fp1 = File.open($mrbtest_io_rfname) + fp2 = File.open($mrbtest_io_wfname) + assert_equal false, FileTest.zero?(fp1) + assert_equal true, FileTest.zero?(fp2) + fp1.close + fp2.close + + assert_raise IOError do + FileTest.zero?(fp1) + end + assert_raise IOError do + FileTest.zero?(fp2) + end + + fp1.closed? && fp2.closed? +end + +assert('FileTest TEST CLEANUP') do + assert_nil MRubyIOTestUtil.io_test_cleanup +end diff --git a/test/io.rb b/test/io.rb new file mode 100644 index 000000000..727c67303 --- /dev/null +++ b/test/io.rb @@ -0,0 +1,237 @@ +## +# IO Test + +assert('IO', '15.2.20') do + assert_equal(Class, IO.class) +end + +assert('IO', '15.2.20.2') do + assert_equal(Object, IO.superclass) +end + +assert('IO', '15.2.20.3') do + assert_include(IO.included_modules, Enumerable) +end + +assert('IO.new') do + IO.new(0) +end + +assert('IO gc check') do + 100.times { IO.new(0) } +end + +assert('IO TEST SETUP') do + MRubyIOTestUtil.io_test_setup +end + +assert('IO.sysopen, IO#close, IO#closed?') do + fd = IO.sysopen $mrbtest_io_rfname + assert_equal Fixnum, fd.class + io = IO.new fd + assert_equal IO, io.class + assert_equal false, io.closed?, "IO not closed" + assert_equal nil, io.close, "IO#close should return nil" + assert_equal true, io.closed?, "IO#closed? should return true" +end + +assert('IO.sysopen, IO#sysread') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + str1 = " " + str2 = io.sysread(5, str1) + assert_equal $mrbtest_io_msg[0,5], str1 + assert_equal $mrbtest_io_msg[0,5], str2 + assert_raise EOFError do + io.sysread(10000) + io.sysread(10000) + end + io.close + io.closed? +end + +assert('IO.sysopen, IO#syswrite') do + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + str = "abcdefg" + len = io.syswrite(str) + assert_equal str.size, len + io.close + io.closed? +end + +assert('IO#_read_buf') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + def io._buf + @buf + end + msg_len = $mrbtest_io_msg.size + 1 + assert_equal '', io._buf + assert_equal $mrbtest_io_msg + "\n", io._read_buf + assert_equal $mrbtest_io_msg + "\n", io._buf + assert_equal 'mruby', io.read(5) + assert_equal 5, io.pos + assert_equal msg_len - 5, io._buf.size + assert_equal $mrbtest_io_msg[5,100] + "\n", io.read + assert_equal 0, io._buf.size + assert_raise EOFError do + io._read_buf + end + assert_equal true, io.eof + assert_equal true, io.eof? + io.close + io.closed? +end + +assert('IO#read argument check') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + assert_raise TypeError do + io.read("str") + end + assert_raise ArgumentError do + io.read(-5) + end + io.close + io.closed? +end + +assert('IO#read') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + assert_equal 'mruby', io.read(5) + assert_equal $mrbtest_io_msg[5,100] + "\n", io.read + assert_equal nil, io.read + io.close + io.closed? +end + +assert('IO#readchar, IO#getc') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + def io._buf + @buf + end + assert_equal 'm', io.readchar + assert_equal 1, io.pos + assert_equal 'r', io.getc + assert_equal 2, io.pos + io.gets + assert_raise EOFError do + io.readchar + end + assert_equal nil, io.getc + io.close + io.closed? +end + +assert('IO#pos=, IO#seek') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + def io._buf + @buf + end + assert_equal 'm', io.getc + assert_equal 1, io.pos + assert_equal 0, io.seek(0) + assert_equal 0, io.pos + io.close + io.closed? +end + + +assert('IO#gets') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + + # gets without arguments + assert_equal $mrbtest_io_msg + "\n", io.gets, "gets without arguments" + assert_equal nil, io.gets, "gets returns nil, when EOF" + + # gets with limit + io.pos = 0 + assert_equal $mrbtest_io_msg[0, 5], io.gets(5), "gets with limit" + + # gets with rs + io.pos = 0 + assert_equal $mrbtest_io_msg[0, 6], io.gets(' '), "gets with rs" + + # gets with rs, limit + io.pos = 0 + assert_equal $mrbtest_io_msg[0, 5], io.gets(' ', 5), "gets with rs, limit" + io.close + assert_equal true, io.closed?, "close success" + + # reading many-lines file. + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + io.write "0123456789" * 2 + "\na" + assert_equal 22, io.pos + io.close + assert_equal true, io.closed? + + fd = IO.sysopen $mrbtest_io_wfname + io = IO.new fd + line = io.gets + + # gets first line + assert_equal "0123456789" * 2 + "\n", line, "gets first line" + assert_equal 21, line.size + assert_equal 21, io.pos + + # gets second line + assert_equal "a", io.gets, "gets second line" + + # gets third line + assert_equal nil, io.gets, "gets third line; returns nil" + + io.close + io.closed? +end + +assert('IO#gets - paragraph mode') do + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + io.write "0" * 10 + "\n" + io.write "1" * 10 + "\n\n" + io.write "2" * 10 + "\n" + assert_equal 34, io.pos + io.close + assert_equal true, io.closed? + + fd = IO.sysopen $mrbtest_io_wfname + io = IO.new fd + para1 = "#{'0' * 10}\n#{'1' * 10}\n\n" + text1 = io.gets("") + assert_equal para1, text1 + para2 = "#{'2' * 10}\n" + text2 = io.gets("") + assert_equal para2, text2 + io.close + io.closed? +end + +assert('IO.popen') do + io = IO.popen("ls") + assert_equal Fixnum, io.pid.class + ls = io.read + assert_equal ls.class, String + assert_include ls, 'AUTHORS' + assert_include ls, 'mrblib' + io.close + io.closed? +end + +assert('IO#fileno') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + assert_equal io.fileno, fd + assert_equal io.to_i, fd + io.close + io.closed? +end + +assert('IO TEST CLEANUP') do + assert_nil MRubyIOTestUtil.io_test_cleanup +end diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c new file mode 100644 index 000000000..71ef715a5 --- /dev/null +++ b/test/mruby_io_test.c @@ -0,0 +1,94 @@ +#include "mruby.h" +#include "mruby/array.h" +#include "mruby/string.h" +#include "mruby/variable.h" +#include +#include +#include + +static mrb_value +mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) +{ + char rfname[] = "tmp.XXXXXXXX"; + char wfname[] = "tmp.XXXXXXXX"; + char msg[] = "mruby io test"; + FILE *fp; + mrb_value ary = mrb_ary_new(mrb); + + mktemp(rfname); + mktemp(wfname); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname)); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname)); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg)); + + mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, rfname)); + mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, wfname)); + mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, msg)); + + fp = fopen(rfname, "w"); + if (fp == NULL) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file"); + return mrb_nil_value(); + } + fprintf(fp, "%s\n", msg); + fclose(fp); + + fp = fopen(wfname, "w"); + if (fp == NULL) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file"); + return mrb_nil_value(); + } + fclose(fp); + + return ary; +} + +static mrb_value +mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self) +{ + mrb_value rfname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_rfname")); + mrb_value wfname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_wfname")); + + if (mrb_type(rfname) == MRB_TT_STRING) { + remove(RSTRING_PTR(rfname)); + } + if (mrb_type(wfname) == MRB_TT_STRING) { + remove(RSTRING_PTR(wfname)); + } + + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_rfname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_wfname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_msg"), mrb_nil_value()); + + return mrb_nil_value(); +} + +static mrb_value +mrb_io_test_file_setup(mrb_state *mrb, mrb_value self) +{ + mrb_value ary = mrb_io_test_io_setup(mrb, self); + symlink("/usr/bin", "test-bin"); + + return ary; +} + +static mrb_value +mrb_io_test_file_cleanup(mrb_state *mrb, mrb_value self) +{ + mrb_io_test_io_cleanup(mrb, self); + remove("test-bin"); + + return mrb_nil_value(); +} + +void +mrb_mruby_io_gem_test(mrb_state* mrb) +{ + struct RClass *io_test = mrb_define_module(mrb, "MRubyIOTestUtil"); + mrb_define_class_method(mrb, io_test, "io_test_setup", mrb_io_test_io_setup, ARGS_NONE()); + mrb_define_class_method(mrb, io_test, "io_test_cleanup", mrb_io_test_io_cleanup, ARGS_NONE()); + + mrb_define_class_method(mrb, io_test, "file_test_setup", mrb_io_test_file_setup, ARGS_NONE()); + mrb_define_class_method(mrb, io_test, "file_test_cleanup", mrb_io_test_file_cleanup, ARGS_NONE()); + +} -- cgit v1.2.3 From b8a23e6be8e8d1047358a4b548ba5241f8503288 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Mon, 1 Apr 2013 09:21:12 +0900 Subject: update README.md --- README.md | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- mrbgem.rake | 2 +- 2 files changed, 182 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 01d29521a..d90669ea1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,185 @@ mruby-io ======== -under construction +IO, File module for mruby + + +## License + +Copyright (c) 2013 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. + +## Implement methods + +### IO + - http://doc.ruby-lang.org/ja/1.9.3/class/IO.html + +| method | mruby-io | memo | +| ------------------------- | -------- | ---- | +| IO.binread | | | +| IO.binwrite | | | +| IO.copy_stream | | | +| IO.new, IO.for_fd, IO.open | o | | +| IO.foreach | | | +| IO.pipe | | | +| IO.popen | o | | +| IO.read | | | +| IO.readlines | | | +| IO.select | | | +| IO.sysopen | o | | +| IO.try_convert | | | +| IO.write | | | +| IO#<< | | | +| IO#advise | | | +| IO#autoclose= | | | +| IO#autoclose? | | | +| IO#binmode | | | +| IO#binmode? | | | +| IO#bytes | | obsolete | +| IO#chars | | obsolete | +| IO#clone, IO#dup | | | +| IO#close | o | | +| IO#close_on_exec= | | | +| IO#close_on_exec? | | | +| IO#close_read | | | +| IO#close_write | | | +| IO#closed? | o | | +| IO#codepoints | | obsolete | +| IO#each_byte | o | | +| IO#each_char | o | | +| IO#each_codepoint | | | +| IO#each_line | o | | +| IO#eof, IO#eof? | o | | +| IO#external_encoding | | | +| IO#fcntl | | | +| IO#fdatasync | | | +| IO#fileno, IO#to_i | | | +| IO#flush | | | +| IO#fsync | | | +| IO#getbyte | | | +| IO#getc | o | | +| IO#gets | o | | +| IO#internal_encoding | | | +| IO#ioctl | | | +| IO#isatty, IO#tty? | | | +| IO#lineno | | | +| IO#lineno= | | | +| IO#lines | | obsolete | +| IO#pid | o | | +| IO#pos, IO#tell | o | | +| IO#pos= | o | | +| IO#print | o | | +| IO#printf | o | | +| IO#putc | | | +| IO#puts | o | | +| IO#read | o | | +| IO#read_nonblock | | | +| IO#readbyte | | | +| IO#readchar | o | | +| IO#readline | o | | +| IO#readlines | o | | +| IO#readpartial | | | +| IO#reopen | | | +| IO#rewind | | | +| IO#seek | o | | +| IO#set_encoding | | | +| IO#stat | | | +| IO#sync | | | +| IO#sync= | | | +| IO#sysread | o | | +| IO#sysseek | o | | +| IO#syswrite | o | | +| IO#to_io | | | +| IO#ungetbyte | | | +| IO#ungetc | o | | +| IO#write | o | | +| IO#write_nonblock | | | + +### File + - http://doc.ruby-lang.org/ja/1.9.3/class/File.html + +| method | mruby-io | memo | +| --------------------------- | -------- | ---- | +| File.absolute_path | | | +| File.atime | | | +| File.basename | o | | +| File.blockdev? | | FileTest | +| File.chardev? | | FileTest | +| File.chmod | | | +| File.chown | | | +| File.ctime | | | +| File.delete, File.unlink | o | | +| File.directory? | o | FileTest | +| File.dirname | o | | +| File.executable? | | FileTest | +| File.executable_real? | | FileTest | +| File.exist?, exists? | o | FileTest | +| File.expand_path | | | +| File.extname | o | | +| File.file? | o | FileTest | +| File.fnmatch, File.fnmatch? | | | +| File.ftype | | | +| File.grpowned? | | FileTest | +| File.identical? | | FileTest | +| File.join | o | | +| File.lchmod | | | +| File.lchown | | | +| File.link | | | +| File.lstat | | | +| File.mtime | | | +| File.new, File.open | o | | +| File.owned? | | FileTest | +| File.path | | | +| File.pipe? | o | FileTest | +| File.readable? | | FileTest | +| File.readable_real? | | FileTest | +| File.readlink | | | +| File.realdirpath | | | +| File.realpath | o | | +| File.rename | o | | +| File.setgid? | | FileTest | +| File.setuid? | | FileTest | +| File.size | o | | +| File.size? | o | FileTest | +| File.socket? | o | FileTest | +| File.split | | | +| File.stat | | | +| File.sticky? | | FileTest | +| File.symlink | | | +| File.symlink? | o | FileTest | +| File.truncate | | | +| File.umask | o | | +| File.utime | | | +| File.world_readable? | | | +| File.world_writable? | | | +| File.writable? | | FileTest | +| File.writable_real? | | FileTest | +| File.zero? | o | FileTest | +| File#atime | | | +| File#chmod | | | +| File#chown | | | +| File#ctime | | | +| File#flock | | | +| File#lstat | | | +| File#mtime | | | +| File#path, File#to_path | o | | +| File#size | | | +| File#truncate | | | diff --git a/mrbgem.rake b/mrbgem.rake index 10e192c45..029af4d26 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -1,6 +1,6 @@ MRuby::Gem::Specification.new('mruby-io') do |spec| spec.license = 'MIT' - spec.authors = 'Internet Initiative Japan' + spec.authors = 'Internet Initiative Japan Inc.' spec.cc.include_paths << "#{build.root}/src" end -- cgit v1.2.3 From 5a425f598b65fa8ddf7b18eccbcf41358753a8e8 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Mon, 1 Apr 2013 10:17:18 +0900 Subject: Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d90669ea1..e05577ef9 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ 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. -## Implement methods +## Implemented methods ### IO - http://doc.ruby-lang.org/ja/1.9.3/class/IO.html -- cgit v1.2.3 From 911003987bc52cebf7625934877bc93cb10056fe Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Tue, 2 Apr 2013 15:32:01 +0900 Subject: add Kernel#open --- mrblib/kernel.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 mrblib/kernel.rb diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb new file mode 100644 index 000000000..2c5f85742 --- /dev/null +++ b/mrblib/kernel.rb @@ -0,0 +1,11 @@ +module Kernel + def open(file, *rest) + raise ArgumentError unless file.is_a?(String) + + if file[0] == "|" + IO.popen(file[1..-1], *rest) + else + File.open(file, *rest) + end + end +end -- cgit v1.2.3 From cc40f93ac8e9bb93ae0a7cf4893c9fd9f3926d21 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Tue, 2 Apr 2013 15:51:36 +0900 Subject: Kernel#open block support --- mrblib/kernel.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb index 2c5f85742..11ac5785f 100644 --- a/mrblib/kernel.rb +++ b/mrblib/kernel.rb @@ -1,11 +1,11 @@ module Kernel - def open(file, *rest) + def open(file, *rest, &block) raise ArgumentError unless file.is_a?(String) if file[0] == "|" - IO.popen(file[1..-1], *rest) + IO.popen(file[1..-1], *rest, &block) else - File.open(file, *rest) + File.open(file, *rest, &block) end end end -- cgit v1.2.3 From da557fbc82577872034cd52fe3bcf45aa13df45e Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 7 Apr 2013 01:55:18 +0900 Subject: add File.expand_path --- mrblib/file.rb | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ run_test.rb | 2 ++ test/file.rb | 23 +++++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/mrblib/file.rb b/mrblib/file.rb index 566085066..5b6986985 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -63,6 +63,71 @@ class File < IO end end + def self.expand_path(path, default_dir = '.') + def concat_path(path, base_path) + if path[0] == "/" + expanded_path = path + elsif path[0] == "~" + if (path[1] == "/" || path[1] == nil) + dir = path[1, path.size] + home_dir = _gethome + + unless home_dir + raise ArgumentError, "couldn't find HOME environment -- expanding '~'" + end + + expanded_path = home_dir + expanded_path += dir if dir + expanded_path += "/" + else + splitted_path = path.split("/") + user = splitted_path[0][1, splitted_path[0].size] + dir = "/" + splitted_path[1, splitted_path.size].join("/") + + home_dir = _gethome(user) + + unless home_dir + raise ArgumentError, "user #{user} doesn't exist" + end + + expanded_path = home_dir + expanded_path += dir if dir + expanded_path += "/" + end + else + expanded_path = concat_path(base_path, _getwd) + expanded_path += "/" + path + end + + expanded_path + end + + expanded_path = concat_path(path, default_dir) + expand_path_array = [] + while expanded_path.include?('//') + expanded_path = expanded_path.gsub('//', '/') + end + + if expanded_path == "/" + expanded_path + else + expanded_path.split('/').each do |path_token| + if path_token == '..' + if expand_path_array.size > 1 + expand_path_array.pop + end + elsif path_token == '.' + # nothing to do. + else + expand_path_array << path_token + end + end + + expand_path = expand_path_array.join("/") + expand_path.empty? ? '/' : expand_path + end + end + def self.directory?(file) FileTest.directory?(file) end diff --git a/run_test.rb b/run_test.rb index e83b504be..d9036a575 100644 --- a/run_test.rb +++ b/run_test.rb @@ -29,5 +29,7 @@ MRuby::Build.new do |conf| conf.gem x unless x =~ /\/mruby-(print|sprintf)$/ end + conf.gem :github => 'iij/mruby-env' + conf.gem File.expand_path(File.dirname(__FILE__)) end diff --git a/test/file.rb b/test/file.rb index f1bef32e5..8fe7636e0 100644 --- a/test/file.rb +++ b/test/file.rb @@ -73,3 +73,26 @@ end assert('File TEST CLEANUP') do assert_nil MRubyIOTestUtil.io_test_cleanup end + +assert('File.expand_path') do + assert_equal "/", File.expand_path("..", "/tmp"), "parent path with base_dir (1)" + assert_equal "/tmp", File.expand_path("..", "/tmp/mruby"), "parent path with base_dir (2)" + + assert_equal "/home", File.expand_path("/home"), "absolute" + assert_equal "/home", File.expand_path("/home", "."), "absolute with base_dir" + + assert_equal "/hoge", File.expand_path("/tmp/..//hoge") + assert_equal "/hoge", File.expand_path("////tmp/..///////hoge") + + assert_equal "/", File.expand_path("../../../..", "/") + assert_equal "/", File.expand_path(([".."] * 100).join("/")) +end + +assert('File.expand_path (with ENV)') do + skip unless Object.const_defined?(:ENV) && ENV['HOME'] + + assert_equal ENV['HOME'], File.expand_path("~/"), "home" + assert_equal ENV['HOME'], File.expand_path("~/", "/"), "home with base_dir" + + assert_equal "#{ENV['HOME']}/user", File.expand_path("user", ENV['HOME']), "relative with base_dir" +end -- cgit v1.2.3 From 814f3305cab2b93c36e1691c8b7439aab6df8c35 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sat, 27 Apr 2013 10:09:05 +0900 Subject: put MRB_ prefix before ARGS_XXX macros --- src/file.c | 22 +++++++++++----------- src/file_test.c | 18 +++++++++--------- src/io.c | 26 +++++++++++++------------- test/mruby_io_test.c | 8 ++++---- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/file.c b/src/file.c index fe6965943..2c6004537 100644 --- a/src/file.c +++ b/src/file.c @@ -273,17 +273,17 @@ mrb_init_file(mrb_state *mrb) io = mrb_class_obj_get(mrb, "IO"); file = mrb_define_class(mrb, "File", io); MRB_SET_INSTANCE_TT(file, MRB_TT_DATA); - mrb_define_class_method(mrb, file, "umask", mrb_file_s_umask, ARGS_REQ(1)); - mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, ARGS_ANY()); - mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, ARGS_ANY()); - mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, ARGS_REQ(2)); - - mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, ARGS_REQ(1)); - mrb_define_class_method(mrb, file, "basename", mrb_file_basename, ARGS_REQ(1)); - mrb_define_class_method(mrb, file, "realpath", mrb_file_realpath, ARGS_REQ(1)|ARGS_OPT(1)); - mrb_define_class_method(mrb, file, "size", mrb_file_size, ARGS_REQ(1)); - mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, ARGS_NONE()); - mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, ARGS_OPT(1)); + mrb_define_class_method(mrb, file, "umask", mrb_file_s_umask, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2)); + + mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "basename", mrb_file_basename, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "realpath", mrb_file_realpath, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, file, "size", mrb_file_size, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1)); cnst = mrb_define_module_under(mrb, file, "Constants"); mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH)); diff --git a/src/file_test.c b/src/file_test.c index dcc6a2fd4..b37edb682 100644 --- a/src/file_test.c +++ b/src/file_test.c @@ -295,13 +295,13 @@ mrb_init_file_test(mrb_state *mrb) f = mrb_define_class(mrb, "FileTest", mrb->object_class); - mrb_define_class_method(mrb, f, "directory?", mrb_filetest_s_directory_p, ARGS_REQ(1)); - mrb_define_class_method(mrb, f, "exist?", mrb_filetest_s_exist_p, ARGS_REQ(1)); - mrb_define_class_method(mrb, f, "exists?", mrb_filetest_s_exist_p, ARGS_REQ(1)); - mrb_define_class_method(mrb, f, "file?", mrb_filetest_s_file_p, ARGS_REQ(1)); - mrb_define_class_method(mrb, f, "pipe?", mrb_filetest_s_pipe_p, ARGS_REQ(1)); - mrb_define_class_method(mrb, f, "size?", mrb_filetest_s_size_p, ARGS_REQ(1)); - mrb_define_class_method(mrb, f, "socket?", mrb_filetest_s_socket_p, ARGS_REQ(1)); - mrb_define_class_method(mrb, f, "symlink?", mrb_filetest_s_symlink_p, ARGS_REQ(1)); - mrb_define_class_method(mrb, f, "zero?", mrb_filetest_s_zero_p, ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "directory?", mrb_filetest_s_directory_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "exist?", mrb_filetest_s_exist_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "exists?", mrb_filetest_s_exist_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "file?", mrb_filetest_s_file_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "pipe?", mrb_filetest_s_pipe_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "size?", mrb_filetest_s_size_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "socket?", mrb_filetest_s_socket_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "symlink?", mrb_filetest_s_symlink_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "zero?", mrb_filetest_s_zero_p, MRB_ARGS_REQ(1)); } diff --git a/src/io.c b/src/io.c index e5fe6a73f..e4e78738b 100644 --- a/src/io.c +++ b/src/io.c @@ -737,19 +737,19 @@ mrb_init_io(mrb_state *mrb) mrb_include_module(mrb, io, mrb_class_get(mrb, "Enumerable")); /* 15.2.20.3 */ - mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, ARGS_ANY()); - mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, ARGS_REQ(1)|ARGS_OPT(2)); - mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, ARGS_ANY()); - - mrb_define_method(mrb, io, "_bless", mrb_io_bless, ARGS_NONE()); - mrb_define_method(mrb, io, "initialize", mrb_io_initialize, ARGS_ANY()); /* 15.2.20.5.21 (x)*/ - mrb_define_method(mrb, io, "sysread", mrb_io_sysread, ARGS_ANY()); - mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, ARGS_REQ(1)); - mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, ARGS_REQ(1)); - mrb_define_method(mrb, io, "close", mrb_io_close, ARGS_NONE()); /* 15.2.20.5.1 */ - mrb_define_method(mrb, io, "closed?", mrb_io_closed, ARGS_NONE()); /* 15.2.20.5.2 */ - mrb_define_method(mrb, io, "pid", mrb_io_pid, ARGS_NONE()); /* 15.2.20.5.2 */ - mrb_define_method(mrb, io, "fileno", mrb_io_fileno, ARGS_NONE()); + mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2)); + mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); + + mrb_define_method(mrb, io, "_bless", mrb_io_bless, MRB_ARGS_NONE()); + mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ + mrb_define_method(mrb, io, "sysread", mrb_io_sysread, MRB_ARGS_ANY()); + mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, io, "close", mrb_io_close, MRB_ARGS_NONE()); /* 15.2.20.5.1 */ + mrb_define_method(mrb, io, "closed?", mrb_io_closed, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ + mrb_define_method(mrb, io, "pid", mrb_io_pid, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ + mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE()); mrb_gv_set(mrb, mrb_intern(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); } diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index 71ef715a5..7c69d5c24 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -85,10 +85,10 @@ void mrb_mruby_io_gem_test(mrb_state* mrb) { struct RClass *io_test = mrb_define_module(mrb, "MRubyIOTestUtil"); - mrb_define_class_method(mrb, io_test, "io_test_setup", mrb_io_test_io_setup, ARGS_NONE()); - mrb_define_class_method(mrb, io_test, "io_test_cleanup", mrb_io_test_io_cleanup, ARGS_NONE()); + mrb_define_class_method(mrb, io_test, "io_test_setup", mrb_io_test_io_setup, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, io_test, "io_test_cleanup", mrb_io_test_io_cleanup, MRB_ARGS_NONE()); - mrb_define_class_method(mrb, io_test, "file_test_setup", mrb_io_test_file_setup, ARGS_NONE()); - mrb_define_class_method(mrb, io_test, "file_test_cleanup", mrb_io_test_file_cleanup, ARGS_NONE()); + mrb_define_class_method(mrb, io_test, "file_test_setup", mrb_io_test_file_setup, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, io_test, "file_test_cleanup", mrb_io_test_file_cleanup, MRB_ARGS_NONE()); } -- cgit v1.2.3 From 62e182318763fe9f6fdf8f81e089d598703c51b3 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 2 May 2013 23:34:36 +0900 Subject: update run_test.rb --- run_test.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/run_test.rb b/run_test.rb index d9036a575..f9627fc28 100644 --- a/run_test.rb +++ b/run_test.rb @@ -20,16 +20,8 @@ end MRuby::Build.new do |conf| toolchain :gcc - conf.gems.clear - - conf.gem "#{root}/mrbgems/mruby-sprintf" - conf.gem "#{root}/mrbgems/mruby-print" - - Dir.glob("#{root}/mrbgems/mruby-*") do |x| - conf.gem x unless x =~ /\/mruby-(print|sprintf)$/ - end + conf.gembox 'default' conf.gem :github => 'iij/mruby-env' - conf.gem File.expand_path(File.dirname(__FILE__)) end -- cgit v1.2.3 From f89ee88a6c4c816a79a2fced1beb0ce616058061 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Thu, 2 May 2013 23:52:57 +0900 Subject: rename mrb_class_obj_get -> mrb_class_get --- include/mruby/ext/io.h | 4 ++-- src/file.c | 2 +- src/file_test.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index 7ecf0a4a4..a104d6d1f 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -47,8 +47,8 @@ struct mrb_io_type { #define FMODE_TEXTMODE 0x00001000 #define FMODE_SETENC_BY_BOM 0x00100000 -#define E_IO_ERROR (mrb_class_obj_get(mrb, "IOError")) -#define E_EOF_ERROR (mrb_class_obj_get(mrb, "EOFError")) +#define E_IO_ERROR (mrb_class_get(mrb, "IOError")) +#define E_EOF_ERROR (mrb_class_get(mrb, "EOFError")) mrb_value mrb_open_file(mrb_state *mrb, int argc, mrb_value *argv, mrb_value io); void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise); diff --git a/src/file.c b/src/file.c index 2c6004537..ae643abac 100644 --- a/src/file.c +++ b/src/file.c @@ -270,7 +270,7 @@ mrb_init_file(mrb_state *mrb) { struct RClass *io, *file, *cnst; - io = mrb_class_obj_get(mrb, "IO"); + io = mrb_class_get(mrb, "IO"); file = mrb_define_class(mrb, "File", io); MRB_SET_INSTANCE_TT(file, MRB_TT_DATA); mrb_define_class_method(mrb, file, "umask", mrb_file_s_umask, MRB_ARGS_REQ(1)); diff --git a/src/file_test.c b/src/file_test.c index b37edb682..0d40c31a8 100644 --- a/src/file_test.c +++ b/src/file_test.c @@ -26,8 +26,8 @@ mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st) mrb_value tmp; mrb_value io_klass, str_klass; - io_klass = mrb_obj_value(mrb_class_obj_get(mrb, "IO")); - str_klass = mrb_obj_value(mrb_class_obj_get(mrb, "String")); + io_klass = mrb_obj_value(mrb_class_get(mrb, "IO")); + str_klass = mrb_obj_value(mrb_class_get(mrb, "String")); tmp = mrb_funcall(mrb, obj, "is_a?", 1, io_klass); if (mrb_test(tmp)) { -- cgit v1.2.3 From 7a94d02e8d8f0a09a3f2dadb956fc34cadd416f3 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 8 May 2013 20:22:14 +0900 Subject: add IO#print --- mrblib/io.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mrblib/io.rb b/mrblib/io.rb index 3c679d3f7..37eaed4be 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -262,6 +262,15 @@ class IO nil end + def print(*args) + i = 0 + len = args.size + while i < len + write args[i].to_s + i += 1 + end + end + def printf(*args) write sprintf(*args) nil -- cgit v1.2.3 From df529a83d6572ed5e06f7d2689ba6ace83699a41 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 8 May 2013 20:22:29 +0900 Subject: add $stdin $stdout $stderr STDIN STDOUT STDERR --- mrblib/io.rb | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/mrblib/io.rb b/mrblib/io.rb index 37eaed4be..011f1dc21 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -278,3 +278,33 @@ class IO alias_method :to_i, :fileno end + +STDIN = IO.open(0, "r") +STDOUT = IO.open(1, "w") +STDERR = IO.open(1, "w") + +$stdin = STDIN +$stdout = STDOUT +$stderr = STDERR + +module Kernel + def print(*args) + STDOUT.print(*args) + end + + def puts(*args) + STDOUT.puts(*args) + end + + def printf(*args) + STDOUT.printf(*args) + end + + def gets(*args) + STDIN.gets(*args) + end + + def getc(*args) + STDIN.getc(*args) + end +end -- cgit v1.2.3 From acc8995060f9972d7cad9e0575619b3f01fd89d1 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 12 May 2013 12:54:32 +0900 Subject: update run_test.rb --- run_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/run_test.rb b/run_test.rb index f9627fc28..89f8d7fb1 100644 --- a/run_test.rb +++ b/run_test.rb @@ -8,7 +8,6 @@ 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 - build_args = ['all', 'test'] if build_args.nil? or build_args.empty? Dir.mkdir 'tmp' unless File.exist?('tmp') unless File.exist?(dir) -- cgit v1.2.3 From c25d386c419546c31ecf8ae09fb3aeb15d511469 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 12 May 2013 13:12:57 +0900 Subject: Use mkstemp instead of mktemp. --- test/mruby_io_test.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index 7c69d5c24..a6fa32d4f 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -5,18 +5,28 @@ #include #include #include +#include static mrb_value mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) { - char rfname[] = "tmp.XXXXXXXX"; - char wfname[] = "tmp.XXXXXXXX"; + char rfname[] = "tmp.mruby-io-test.XXXXXXXX"; + char wfname[] = "tmp.mruby-io-test.XXXXXXXX"; char msg[] = "mruby io test"; + mode_t mask; + int fd0 = -1, fd1 = -1; FILE *fp; mrb_value ary = mrb_ary_new(mrb); - mktemp(rfname); - mktemp(wfname); + mask = umask(077); + fd0 = mkstemp(rfname); + fd1 = mkstemp(wfname); + if (fd0 == -1 || fd1 == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file"); + return mrb_nil_value(); + } + umask(mask); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname)); mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname)); mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg)); -- cgit v1.2.3 From 49cc9c7cfa55f4aa11fc1ce39539429e97e536b4 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 12 May 2013 14:01:53 +0900 Subject: Use strncpy instead of strcpy. --- src/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/file.c b/src/file.c index ae643abac..f90204585 100644 --- a/src/file.c +++ b/src/file.c @@ -259,7 +259,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } result = mrb_str_buf_new(mrb, strlen(home)); - strcpy( RSTRING_PTR(result), home); + strncpy(RSTRING_PTR(result), home, strlen(home)); mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result))); return result; -- cgit v1.2.3 From d39a05e68e0288d648e8ecf9574799593943e55c Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 12 May 2013 14:14:48 +0900 Subject: remove unused variable. --- src/io.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/io.c b/src/io.c index e4e78738b..d1ba729aa 100644 --- a/src/io.c +++ b/src/io.c @@ -303,7 +303,7 @@ mrb_value mrb_io_initialize(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; - mrb_int fd, flags; + mrb_int fd; mrb_value mode, opt; DATA_TYPE(io) = &mrb_io_type; @@ -319,8 +319,6 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) opt = mrb_hash_new(mrb); } - flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); - mrb_iv_set(mrb, io, mrb_intern(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); mrb_iv_set(mrb, io, mrb_intern(mrb, "@pos"), mrb_fixnum_value(0)); @@ -328,8 +326,7 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) if (fptr == NULL) { fptr = mrb_io_alloc(mrb); } - fptr->fd = fd; - + fptr->fd = fd; DATA_PTR(io) = fptr; return io; -- cgit v1.2.3 From 14e1992ed0c1b1244bc0c802fae8fe3cd88e848f Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 12 May 2013 14:15:00 +0900 Subject: add null check --- src/file.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/file.c b/src/file.c index f90204585..02991eb98 100644 --- a/src/file.c +++ b/src/file.c @@ -250,6 +250,10 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } } + if (home == NULL) { + return mrb_nil_value(); + } + if (!mrb_file_is_absolute_path(home)) { if (argc && strlen(cuser) > 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%s", cuser); -- cgit v1.2.3 From 55b6ef43c5f8735b2cb2bc7d3d813062d08fb934 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 12 May 2013 14:23:48 +0900 Subject: add return value check of fseek --- src/file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/file.c b/src/file.c index 02991eb98..ad7c8f574 100644 --- a/src/file.c +++ b/src/file.c @@ -200,7 +200,10 @@ mrb_file_size(mrb_state *mrb, mrb_value klass) return mrb_nil_value(); } - fseek(fp, 0, SEEK_END); + if (fseek(fp, 0, SEEK_END) != 0) { + mrb_sys_fail(mrb, "mrb_file_size failed."); + return mrb_nil_value(); + } filesize = (mrb_int) ftell(fp); fclose(fp); -- cgit v1.2.3 From e277079616bbc54f70bbf0a312a237f91a3d4f35 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 12 May 2013 14:50:31 +0900 Subject: update run_test.rb --- run_test.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/run_test.rb b/run_test.rb index 89f8d7fb1..444d18fda 100644 --- a/run_test.rb +++ b/run_test.rb @@ -3,8 +3,6 @@ # mrbgems test runner # -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 @@ -21,6 +19,7 @@ MRuby::Build.new do |conf| toolchain :gcc conf.gembox 'default' - conf.gem :github => 'iij/mruby-env' + conf.gem :git => 'https://github.com/iij/mruby-env.git' + conf.gem File.expand_path(File.dirname(__FILE__)) end -- cgit v1.2.3 From 0a21d9ec920675bdbfa4f7705764f6f648fdd335 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 12 May 2013 14:58:12 +0900 Subject: bufix of mrb_file__gethome() --- src/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/file.c b/src/file.c index ad7c8f574..2585e314e 100644 --- a/src/file.c +++ b/src/file.c @@ -265,8 +265,8 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } } - result = mrb_str_buf_new(mrb, strlen(home)); - strncpy(RSTRING_PTR(result), home, strlen(home)); + result = mrb_str_buf_new(mrb, MAXPATHLEN); + strncpy(RSTRING_PTR(result), home, MAXPATHLEN); mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result))); return result; -- cgit v1.2.3 From 1272df7cb6db0603113cabd5eee126739bf81115 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 2 Jun 2013 12:03:45 +0900 Subject: fix IO#eof? method (consider the read buffer) --- mrblib/io.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 011f1dc21..990a4b92d 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -55,7 +55,8 @@ class IO end def eof? - # XXX: @buf のことを考えなくてよい?? + return true if @buf && @buf.size > 0 + ret = false char = '' -- cgit v1.2.3 From 5625e44371e27510c99fae98f1aa353c57aafea9 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sun, 2 Jun 2013 13:28:22 +0900 Subject: add method: IO#select --- src/io.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/io.c b/src/io.c index d1ba729aa..d5d4cc07f 100644 --- a/src/io.c +++ b/src/io.c @@ -551,12 +551,22 @@ time2timeval(mrb_state *mrb, mrb_value time) return t; } +static int +mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) +{ + mrb_value buf = mrb_iv_get(mrb, io, mrb_intern(mrb, "@buf")); + if (mrb_type(buf) == MRB_TT_STRING && RSTRING_LEN(buf) > 0) { + return 1; + } + return 0; +} + static mrb_value -mrb_io_select(mrb_state *mrb, mrb_value klass) +mrb_io_s_select(mrb_state *mrb, mrb_value klass) { mrb_value *argv; int argc; - mrb_value read, write, except, timeout, list; + mrb_value read, read_io, write, except, timeout, list; struct timeval *tp, timerec; fd_set pset, rset, wset, eset; fd_set *rp, *wp, *ep; @@ -599,14 +609,13 @@ mrb_io_select(mrb_state *mrb, mrb_value klass) rp = &rset; FD_ZERO(rp); for (i = 0; i < RARRAY_LEN(read); i++) { - fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(read)[i], &mrb_io_type); + read_io = RARRAY_PTR(read)[i]; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, read_io, &mrb_io_type); FD_SET(fptr->fd, rp); - /* XXX: ..... - if (READ_DATA_PENDING(fptr->f)) { + if (!mrb_io_read_data_pending(mrb, read_io)) { pending++; - FD_SET(fileno(fptr->f), &pset); + FD_SET(fptr->fd, &pset); } - */ if (max < fptr->fd) max = fptr->fd; } @@ -737,6 +746,7 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2)); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_method(mrb, io, "_bless", mrb_io_bless, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ -- cgit v1.2.3 From 4f3a749da10e896f1faa03cef62b79624c575be7 Mon Sep 17 00:00:00 2001 From: Takashi Sogabe Date: Wed, 26 Jun 2013 15:24:23 +0900 Subject: Fix incorrect condition for pendig-IO --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index d5d4cc07f..18cc5e66e 100644 --- a/src/io.c +++ b/src/io.c @@ -612,7 +612,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass) read_io = RARRAY_PTR(read)[i]; fptr = (struct mrb_io *)mrb_get_datatype(mrb, read_io, &mrb_io_type); FD_SET(fptr->fd, rp); - if (!mrb_io_read_data_pending(mrb, read_io)) { + if (mrb_io_read_data_pending(mrb, read_io)) { pending++; FD_SET(fptr->fd, &pset); } -- cgit v1.2.3 From c49541058c40623b0c337a7e95193142c8dc9947 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 8 Aug 2013 13:58:47 +0900 Subject: use lstat(2) to check if it's a symlink --- src/file_test.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/file_test.c b/src/file_test.c index 0d40c31a8..872f7aebc 100644 --- a/src/file_test.c +++ b/src/file_test.c @@ -21,7 +21,7 @@ extern struct mrb_data_type mrb_io_type; static int -mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st) +mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) { mrb_value tmp; mrb_value io_klass, str_klass; @@ -44,12 +44,28 @@ mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st) tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); if (mrb_test(tmp)) { - return stat(mrb_string_value_cstr(mrb, &obj), st); + if (do_lstat) { + return lstat(mrb_str_to_cstr(mrb, obj), st); + } else { + return stat(mrb_str_to_cstr(mrb, obj), st); + } } return -1; } +static int +mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st) +{ + return mrb_stat0(mrb, obj, st, 0); +} + +static int +mrb_lstat(mrb_state *mrb, mrb_value obj, struct stat *st) +{ + return mrb_stat0(mrb, obj, st, 1); +} + /* * Document-method: directory? * @@ -142,7 +158,7 @@ mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "o", &obj); - if (mrb_stat(mrb, obj, &st) < 0) + if (mrb_lstat(mrb, obj, &st) == -1) return mrb_false_value(); if (S_ISLNK(st.st_mode)) return mrb_true_value(); -- cgit v1.2.3 From 5e8021bedba95813e91693c85e1cad829355a352 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 8 Aug 2013 14:00:02 +0900 Subject: tests for File.socket? and File.symlink? --- test/file_test.rb | 4 ++-- test/mruby_io_test.c | 63 ++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/test/file_test.rb b/test/file_test.rb index 296679a6b..dc92505ca 100644 --- a/test/file_test.rb +++ b/test/file_test.rb @@ -56,11 +56,11 @@ assert("FileTest.size?") do end assert("FileTest.socket?") do - skip + assert_true FileTest.socket?($mrbtest_io_socketname) end assert("FileTest.symlink?") do - skip + assert_true FileTest.symlink?($mrbtest_io_symlinkname) end assert("FileTest.zero?") do diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index a6fa32d4f..0e9ccc696 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -1,27 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include + #include "mruby.h" #include "mruby/array.h" #include "mruby/string.h" #include "mruby/variable.h" -#include -#include -#include -#include static mrb_value mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) { - char rfname[] = "tmp.mruby-io-test.XXXXXXXX"; - char wfname[] = "tmp.mruby-io-test.XXXXXXXX"; + char rfname[] = "tmp.mruby-io-test.XXXXXXXX"; + char wfname[] = "tmp.mruby-io-test.XXXXXXXX"; + char symlinkname[] = "tmp.mruby-io-test.XXXXXXXX"; + char socketname[] = "tmp.mruby-io-test.XXXXXXXX"; char msg[] = "mruby io test"; mode_t mask; - int fd0 = -1, fd1 = -1; + int fd0, fd1, fd2, fd3; FILE *fp; - mrb_value ary = mrb_ary_new(mrb); + struct sockaddr_un sun0; mask = umask(077); fd0 = mkstemp(rfname); fd1 = mkstemp(wfname); - if (fd0 == -1 || fd1 == -1) { + fd2 = mkstemp(symlinkname); + fd3 = mkstemp(socketname); + if (fd0 == -1 || fd1 == -1 || fd2 == -1 || fd3 == -1) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file"); return mrb_nil_value(); } @@ -29,12 +37,10 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname)); mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname)); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_symlinkname"), mrb_str_new_cstr(mrb, symlinkname)); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_socketname"), mrb_str_new_cstr(mrb, socketname)); mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg)); - mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, rfname)); - mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, wfname)); - mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, msg)); - fp = fopen(rfname, "w"); if (fp == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file"); @@ -50,7 +56,26 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) } fclose(fp); - return ary; + unlink(symlinkname); + close(fd2); + if (symlink("hoge", symlinkname) == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link"); + } + + unlink(socketname); + close(fd3); + fd3 = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd3 == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a socket"); + } + sun0.sun_family = AF_UNIX; + snprintf(sun0.sun_path, sizeof(sun0.sun_path), "%s", socketname); + if (bind(fd3, (struct sockaddr *)&sun0, sizeof(sun0)) == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a socket bi"); + } + close(fd3); + + return mrb_true_value(); } static mrb_value @@ -58,6 +83,8 @@ mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self) { mrb_value rfname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_rfname")); mrb_value wfname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_wfname")); + mrb_value symlinkname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_symlinkname")); + mrb_value socketname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_socketname")); if (mrb_type(rfname) == MRB_TT_STRING) { remove(RSTRING_PTR(rfname)); @@ -65,9 +92,17 @@ mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self) if (mrb_type(wfname) == MRB_TT_STRING) { remove(RSTRING_PTR(wfname)); } + if (mrb_type(symlinkname) == MRB_TT_STRING) { + remove(RSTRING_PTR(symlinkname)); + } + if (mrb_type(socketname) == MRB_TT_STRING) { + remove(RSTRING_PTR(socketname)); + } mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_rfname"), mrb_nil_value()); mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_wfname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_symlinkname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_socketname"), mrb_nil_value()); mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_msg"), mrb_nil_value()); return mrb_nil_value(); -- cgit v1.2.3 From 9dc875f2460433e5f69eaf0a2dbb560e414db789 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 23 Aug 2013 16:00:08 +0900 Subject: add `cmd` (command output expression). --- mrblib/kernel.rb | 4 ++++ test/io.rb | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb index 11ac5785f..484b50160 100644 --- a/mrblib/kernel.rb +++ b/mrblib/kernel.rb @@ -1,4 +1,8 @@ module Kernel + def self.`(cmd) + IO.popen(cmd) { |io| io.read } + end + def open(file, *rest, &block) raise ArgumentError unless file.is_a?(String) diff --git a/test/io.rb b/test/io.rb index 727c67303..315f3ea79 100644 --- a/test/io.rb +++ b/test/io.rb @@ -232,6 +232,10 @@ assert('IO#fileno') do io.closed? end +assert('`cmd`') do + assert_equal `echo foo`, "foo\n" +end + assert('IO TEST CLEANUP') do assert_nil MRubyIOTestUtil.io_test_cleanup end -- cgit v1.2.3 From 713aa48cf91d96022fbb73c117260d653a83dac2 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 30 Aug 2013 17:04:40 +0900 Subject: STDERR's file descriptor is 2. closes #1 --- mrblib/io.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 990a4b92d..1fcd44b28 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -282,7 +282,7 @@ end STDIN = IO.open(0, "r") STDOUT = IO.open(1, "w") -STDERR = IO.open(1, "w") +STDERR = IO.open(2, "w") $stdin = STDIN $stdout = STDOUT -- cgit v1.2.3 From 47a610e688c4e7eac3267e5fd776b7032406fdae Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 30 Aug 2013 19:09:36 +0900 Subject: use array parameter on IO.open. --- mrblib/io.rb | 6 +++--- test/io.rb | 24 ++++++++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 1fcd44b28..ca687aee0 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -11,10 +11,10 @@ class IO BUF_SIZE = 4096 - def self.open(fd, mode = "r", opt = {}, &block) - io = self.new(fd, mode, opt) + def self.open(*args, &block) + io = self.new(*args) - return io unless block + return io unless block begin yield io diff --git a/test/io.rb b/test/io.rb index 315f3ea79..77b6bc430 100644 --- a/test/io.rb +++ b/test/io.rb @@ -1,6 +1,10 @@ ## # IO Test +assert('IO TEST SETUP') do + MRubyIOTestUtil.io_test_setup +end + assert('IO', '15.2.20') do assert_equal(Class, IO.class) end @@ -13,6 +17,22 @@ assert('IO', '15.2.20.3') do assert_include(IO.included_modules, Enumerable) end +assert('IO.open', '15.2.20.4.1') do + fd = IO.sysopen $mrbtest_io_rfname + assert_equal Fixnum, fd.class + io = IO.open fd + assert_equal IO, io.class + assert_equal $mrbtest_io_msg+"\n", io.read + io.close + + fd = IO.sysopen $mrbtest_io_rfname + IO.open(fd) do |io| + assert_equal $mrbtest_io_msg+"\n", io.read + end + + true +end + assert('IO.new') do IO.new(0) end @@ -21,10 +41,6 @@ assert('IO gc check') do 100.times { IO.new(0) } end -assert('IO TEST SETUP') do - MRubyIOTestUtil.io_test_setup -end - assert('IO.sysopen, IO#close, IO#closed?') do fd = IO.sysopen $mrbtest_io_rfname assert_equal Fixnum, fd.class -- cgit v1.2.3 From c4e3c46e865d6363d3000eb833cccfd23b2588ab Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Wed, 25 Sep 2013 13:26:49 +0200 Subject: Catch up with API changes on mrb_intern() -> mrb_intern_cstr() --- src/io.c | 12 ++++++------ test/mruby_io_test.c | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/io.c b/src/io.c index 18cc5e66e..18ed085c1 100644 --- a/src/io.c +++ b/src/io.c @@ -282,8 +282,8 @@ retry: fd = pw[1]; } - mrb_iv_set(mrb, io, mrb_intern(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - mrb_iv_set(mrb, io, mrb_intern(mrb, "@pos"), mrb_fixnum_value(0)); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr = mrb_io_alloc(mrb); fptr->fd = fd; @@ -319,8 +319,8 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) opt = mrb_hash_new(mrb); } - mrb_iv_set(mrb, io, mrb_intern(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - mrb_iv_set(mrb, io, mrb_intern(mrb, "@pos"), mrb_fixnum_value(0)); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr = DATA_PTR(io); if (fptr == NULL) { @@ -554,7 +554,7 @@ time2timeval(mrb_state *mrb, mrb_value time) static int mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) { - mrb_value buf = mrb_iv_get(mrb, io, mrb_intern(mrb, "@buf")); + mrb_value buf = mrb_iv_get(mrb, io, mrb_intern_cstr(mrb, "@buf")); if (mrb_type(buf) == MRB_TT_STRING && RSTRING_LEN(buf) > 0) { return 1; } @@ -758,5 +758,5 @@ mrb_init_io(mrb_state *mrb) mrb_define_method(mrb, io, "pid", mrb_io_pid, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE()); - mrb_gv_set(mrb, mrb_intern(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); } diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index 0e9ccc696..68c60f98c 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -35,11 +35,11 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) } umask(mask); - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname)); - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname)); - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_symlinkname"), mrb_str_new_cstr(mrb, symlinkname)); - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_socketname"), mrb_str_new_cstr(mrb, socketname)); - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_str_new_cstr(mrb, symlinkname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_str_new_cstr(mrb, socketname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg)); fp = fopen(rfname, "w"); if (fp == NULL) { @@ -81,10 +81,10 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) static mrb_value mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self) { - mrb_value rfname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_rfname")); - mrb_value wfname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_wfname")); - mrb_value symlinkname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_symlinkname")); - mrb_value socketname = mrb_gv_get(mrb, mrb_intern(mrb, "$mrbtest_io_socketname")); + mrb_value rfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname")); + mrb_value wfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname")); + mrb_value symlinkname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname")); + mrb_value socketname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname")); if (mrb_type(rfname) == MRB_TT_STRING) { remove(RSTRING_PTR(rfname)); @@ -99,11 +99,11 @@ mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self) remove(RSTRING_PTR(socketname)); } - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_rfname"), mrb_nil_value()); - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_wfname"), mrb_nil_value()); - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_symlinkname"), mrb_nil_value()); - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_socketname"), mrb_nil_value()); - mrb_gv_set(mrb, mrb_intern(mrb, "$mrbtest_io_msg"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_nil_value()); return mrb_nil_value(); } -- cgit v1.2.3 From e27fb544dfea1c596a7819e5d467129374b3a6fd Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 26 Sep 2013 10:59:40 +0900 Subject: suppress a warning and fix a possible segv. --- src/file.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/src/file.c b/src/file.c index 2585e314e..0fed5b21a 100644 --- a/src/file.c +++ b/src/file.c @@ -235,41 +235,31 @@ mrb_file_is_absolute_path(const char *path) static mrb_value mrb_file__gethome(mrb_state *mrb, mrb_value klass) { - mrb_value username, result; - char *cuser, *home; + mrb_value username; int argc; - struct passwd *pwd; + char *home; argc = mrb_get_args(mrb, "|S", &username); - if (argc == 0) { home = getenv("HOME"); - } else { - cuser = mrb_str_to_cstr(mrb, username); - if ((pwd = getpwnam(cuser)) == NULL) { + if (home == NULL) { return mrb_nil_value(); - } else { - home = pwd->pw_dir; } - } - - if (home == NULL) { - return mrb_nil_value(); - } - - if (!mrb_file_is_absolute_path(home)) { - if (argc && strlen(cuser) > 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%s", cuser); - } else { + if (!mrb_file_is_absolute_path(home)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home"); } + } else { + const char *cuser = mrb_str_to_cstr(mrb, username); + struct passwd *pwd = getpwnam(cuser); + if (pwd == NULL) { + return mrb_nil_value(); + } + home = pwd->pw_dir; + if (!mrb_file_is_absolute_path(home)) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%S", username); + } } - - result = mrb_str_buf_new(mrb, MAXPATHLEN); - strncpy(RSTRING_PTR(result), home, MAXPATHLEN); - mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result))); - - return result; + return mrb_str_new_cstr(mrb, home); } void -- cgit v1.2.3 From 140da1c6caf1ba98f961470a1d87ba7e14f0fb25 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 26 Sep 2013 18:31:02 +0900 Subject: remove duplicated white spaces. --- src/io.c | 38 +++++++++++++++++++------------------- test/mruby_io_test.c | 28 ++++++++++++++-------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/io.c b/src/io.c index 18ed085c1..8044874e9 100644 --- a/src/io.c +++ b/src/io.c @@ -282,13 +282,13 @@ retry: fd = pw[1]; } - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr = mrb_io_alloc(mrb); - fptr->fd = fd; - fptr->fd2 = write_fd; - fptr->pid = pid; + fptr->fd = fd; + fptr->fd2 = write_fd; + fptr->pid = pid; DATA_TYPE(io) = &mrb_io_type; DATA_PTR(io) = fptr; @@ -319,8 +319,8 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) opt = mrb_hash_new(mrb); } - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr = DATA_PTR(io); if (fptr == NULL) { @@ -554,7 +554,7 @@ time2timeval(mrb_state *mrb, mrb_value time) static int mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) { - mrb_value buf = mrb_iv_get(mrb, io, mrb_intern_cstr(mrb, "@buf")); + mrb_value buf = mrb_iv_get(mrb, io, mrb_intern_cstr(mrb, "@buf")); if (mrb_type(buf) == MRB_TT_STRING && RSTRING_LEN(buf) > 0) { return 1; } @@ -748,15 +748,15 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); - mrb_define_method(mrb, io, "_bless", mrb_io_bless, MRB_ARGS_NONE()); - mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ - mrb_define_method(mrb, io, "sysread", mrb_io_sysread, MRB_ARGS_ANY()); - mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, io, "close", mrb_io_close, MRB_ARGS_NONE()); /* 15.2.20.5.1 */ - mrb_define_method(mrb, io, "closed?", mrb_io_closed, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ - mrb_define_method(mrb, io, "pid", mrb_io_pid, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ - mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE()); - - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); + mrb_define_method(mrb, io, "_bless", mrb_io_bless, MRB_ARGS_NONE()); + mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ + mrb_define_method(mrb, io, "sysread", mrb_io_sysread, MRB_ARGS_ANY()); + mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, io, "close", mrb_io_close, MRB_ARGS_NONE()); /* 15.2.20.5.1 */ + mrb_define_method(mrb, io, "closed?", mrb_io_closed, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ + mrb_define_method(mrb, io, "pid", mrb_io_pid, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ + mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE()); + + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); } diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index 68c60f98c..6a3b20f62 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -35,11 +35,11 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) } umask(mask); - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname)); - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname)); - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_str_new_cstr(mrb, symlinkname)); - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_str_new_cstr(mrb, socketname)); - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_str_new_cstr(mrb, symlinkname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_str_new_cstr(mrb, socketname)); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg)); fp = fopen(rfname, "w"); if (fp == NULL) { @@ -81,10 +81,10 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) static mrb_value mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self) { - mrb_value rfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname")); - mrb_value wfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname")); - mrb_value symlinkname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname")); - mrb_value socketname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname")); + mrb_value rfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname")); + mrb_value wfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname")); + mrb_value symlinkname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname")); + mrb_value socketname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname")); if (mrb_type(rfname) == MRB_TT_STRING) { remove(RSTRING_PTR(rfname)); @@ -99,11 +99,11 @@ mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self) remove(RSTRING_PTR(socketname)); } - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_nil_value()); - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_nil_value()); - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_nil_value()); - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_nil_value()); - mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_nil_value()); + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_nil_value()); return mrb_nil_value(); } -- cgit v1.2.3 From b4f0a68fba4b222461ca79feb94d94e325341129 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 30 Sep 2013 10:17:21 +0900 Subject: add File#flock. --- README.md | 2 +- src/file.c | 35 +++++++++++++++++++++++++++++++++++ test/file.rb | 11 +++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e05577ef9..51b6d1851 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ DEALINGS IN THE SOFTWARE. | File#chmod | | | | File#chown | | | | File#ctime | | | -| File#flock | | | +| File#flock | o | | | File#lstat | | | | File#mtime | | | | File#path, File#to_path | o | | diff --git a/src/file.c b/src/file.c index 0fed5b21a..5c46aa965 100644 --- a/src/file.c +++ b/src/file.c @@ -36,6 +36,9 @@ #define STAT(p, s) stat(p, s) +extern mrb_value mrb_io_fileno(mrb_state *mrb, mrb_value io); + + mrb_value mrb_file_s_umask(mrb_state *mrb, mrb_value klass) { @@ -262,6 +265,36 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) return mrb_str_new_cstr(mrb, home); } +mrb_value +mrb_file_flock(mrb_state *mrb, mrb_value self) +{ + mrb_int operation; + int fd; + + mrb_get_args(mrb, "i", &operation); + fd = mrb_fixnum(mrb_io_fileno(mrb, self)); + + while (flock(fd, operation) == -1) { + switch (errno) { + case EINTR: + /* retry */ + break; + case EAGAIN: /* NetBSD */ +#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: /* FreeBSD OpenBSD Linux */ +#endif + if (operation & LOCK_NB) { + return mrb_false_value(); + } + /* FALLTHRU - should not happen */ + default: + mrb_sys_fail(mrb, "flock failed"); + break; + } + } + return mrb_fixnum_value(0); +} + void mrb_init_file(mrb_state *mrb) { @@ -282,6 +315,8 @@ mrb_init_file(mrb_state *mrb) mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, MRB_ARGS_NONE()); mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1)); + mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1)); + cnst = mrb_define_module_under(mrb, file, "Constants"); mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH)); mrb_define_const(mrb, cnst, "LOCK_EX", mrb_fixnum_value(LOCK_EX)); diff --git a/test/file.rb b/test/file.rb index 8fe7636e0..4b3458d1a 100644 --- a/test/file.rb +++ b/test/file.rb @@ -49,6 +49,17 @@ assert('File.extname') do assert_equal '', File.extname('.foo') end +assert('IO#flock') do + f = File.open $mrbtest_io_rfname + assert_equal(f.flock(File::LOCK_SH), 0) + assert_equal(f.flock(File::LOCK_UN), 0) + assert_equal(f.flock(File::LOCK_EX | File::LOCK_UN), 0) + assert_equal(f.flock(File::LOCK_UN), 0) + f.close + true +end + + assert('File.size') do File.size($mrbtest_io_rfname) == $mrbtest_io_msg.size + 1 and File.size($mrbtest_io_wfname) == 0 -- cgit v1.2.3 From d75d23294d31c3fea16f849a73823fd9d3f17dd9 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 30 Sep 2013 10:36:29 +0900 Subject: fix descriptor leakage. --- src/io.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/io.c b/src/io.c index 8044874e9..284d90877 100644 --- a/src/io.c +++ b/src/io.c @@ -195,7 +195,8 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) struct mrb_io *fptr; const char *pname; int pid, flags, fd, write_fd = -1; - int pr[2], pw[2]; + int pr[2] = { -1, -1 }; + int pw[2] = { -1, -1 }; int doexec; mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); @@ -206,10 +207,13 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) doexec = (strcmp("-", pname) != 0); - if (((flags & FMODE_READABLE) && pipe(pr) == -1) - || ((flags & FMODE_WRITABLE) && pipe(pw) == -1)) { - mrb_sys_fail(mrb, "pipe_open failed."); - return mrb_nil_value(); + if ((flags & FMODE_READABLE) && pipe(pr) == -1) { + mrb_sys_fail(mrb, "pipe"); + } + if ((flags & FMODE_WRITABLE) && pipe(pw) == -1) { + if (pr[0] != -1) close(pr[0]); + if (pr[1] != -1) close(pr[1]); + mrb_sys_fail(mrb, "pipe"); } if (!doexec) { -- cgit v1.2.3 From adb3bd669831ed1c04708076072313a209e2d848 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 30 Sep 2013 10:55:09 +0900 Subject: don't retry when we cannot fork(2). EAGAIN indicates the system is under heavy load. Retrying make things worse. --- src/io.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/io.c b/src/io.c index 284d90877..d59d95b97 100644 --- a/src/io.c +++ b/src/io.c @@ -198,6 +198,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) int pr[2] = { -1, -1 }; int pw[2] = { -1, -1 }; int doexec; + int saved_errno; mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); @@ -223,7 +224,6 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) fflush(stderr); } -retry: switch (pid = fork()) { case 0: /* child */ if (flags & FMODE_READABLE) { @@ -250,24 +250,6 @@ retry: _exit(127); } return mrb_nil_value(); - case -1: /* error */ - if (errno == EAGAIN) { - goto retry; - } else { - int e = errno; - if (flags & FMODE_READABLE) { - close(pr[0]); - close(pr[1]); - } - if (flags & FMODE_WRITABLE) { - close(pw[0]); - close(pw[1]); - } - - errno = e; - mrb_sys_fail(mrb, "pipe_open failed."); - } - break; default: /* parent */ if (pid < 0) { mrb_sys_fail(mrb, "pipe_open failed."); @@ -298,6 +280,19 @@ retry: DATA_PTR(io) = fptr; return io; } + case -1: /* error */ + saved_errno = errno; + if (flags & FMODE_READABLE) { + close(pr[0]); + close(pr[1]); + } + if (flags & FMODE_WRITABLE) { + close(pw[0]); + close(pw[1]); + } + errno = saved_errno; + mrb_sys_fail(mrb, "pipe_open failed."); + break; } return mrb_nil_value(); -- cgit v1.2.3 From 97899a6922a016d4e488f929f009db78d46d7b1d Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 30 Sep 2013 11:18:22 +0900 Subject: style --- src/io.c | 64 +++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/src/io.c b/src/io.c index d59d95b97..e156733dd 100644 --- a/src/io.c +++ b/src/io.c @@ -162,9 +162,9 @@ mrb_io_alloc(mrb_state *mrb) struct mrb_io *fptr; fptr = (struct mrb_io *)mrb_malloc(mrb, sizeof(struct mrb_io)); - fptr->fd = -1; - fptr->fd2 = -1; - fptr->pid = 0; + fptr->fd = -1; + fptr->fd2 = -1; + fptr->pid = 0; return fptr; } @@ -188,7 +188,7 @@ io_open(mrb_state *mrb, mrb_value path, int flags, int perm) mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { - mrb_value cmd, io; + mrb_value cmd, io, result; mrb_value mode = mrb_str_new_cstr(mrb, "r"); mrb_value opt = mrb_hash_new(mrb); @@ -224,6 +224,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) fflush(stderr); } + result = mrb_nil_value(); switch (pid = fork()) { case 0: /* child */ if (flags & FMODE_READABLE) { @@ -240,7 +241,6 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) close(pw[0]); } } - if (doexec) { for (fd = 3; fd < NOFILE; fd++) { close(fd); @@ -249,37 +249,36 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) mrb_raisef(mrb, E_IO_ERROR, "command not found: %s", pname); _exit(127); } - return mrb_nil_value(); + result = mrb_nil_value(); + break; + default: /* parent */ - if (pid < 0) { - mrb_sys_fail(mrb, "pipe_open failed."); - return mrb_nil_value(); + if ((flags & FMODE_READABLE) && (flags & FMODE_WRITABLE)) { + close(pr[1]); + fd = pr[0]; + close(pw[0]); + write_fd = pw[1]; + } else if (flags & FMODE_READABLE) { + close(pr[1]); + fd = pr[0]; } else { - if ((flags & FMODE_READABLE) && (flags & FMODE_WRITABLE)) { - close(pr[1]); - fd = pr[0]; - close(pw[0]); - write_fd = pw[1]; - } else if (flags & FMODE_READABLE) { - close(pr[1]); - fd = pr[0]; - } else { - close(pw[0]); - fd = pw[1]; - } + close(pw[0]); + fd = pw[1]; + } - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); - fptr = mrb_io_alloc(mrb); - fptr->fd = fd; - fptr->fd2 = write_fd; - fptr->pid = pid; + fptr = mrb_io_alloc(mrb); + fptr->fd = fd; + fptr->fd2 = write_fd; + fptr->pid = pid; + + DATA_TYPE(io) = &mrb_io_type; + DATA_PTR(io) = fptr; + result = io; + break; - DATA_TYPE(io) = &mrb_io_type; - DATA_PTR(io) = fptr; - return io; - } case -1: /* error */ saved_errno = errno; if (flags & FMODE_READABLE) { @@ -294,8 +293,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) mrb_sys_fail(mrb, "pipe_open failed."); break; } - - return mrb_nil_value(); + return result; } mrb_value -- cgit v1.2.3 From 8b48e2b4a42c9e1c697f94d3bb362a12484fe2e7 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 30 Sep 2013 11:56:15 +0900 Subject: syswrite must write to fd2 if it is properly set. closes #3. --- src/io.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/io.c b/src/io.c index e156733dd..b80ff63b8 100644 --- a/src/io.c +++ b/src/io.c @@ -470,7 +470,7 @@ mrb_io_syswrite(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; mrb_value str, buf; - int length; + int fd, length; mrb_get_args(mrb, "S", &str); if (mrb_type(str) != MRB_TT_STRING) { @@ -480,7 +480,12 @@ mrb_io_syswrite(mrb_state *mrb, mrb_value io) } fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); - length = write(fptr->fd, RSTRING_PTR(buf), RSTRING_LEN(buf)); + if (fptr->fd2 == -1) { + fd = fptr->fd; + } else { + fd = fptr->fd2; + } + length = write(fd, RSTRING_PTR(buf), RSTRING_LEN(buf)); return mrb_fixnum_value(length); } -- cgit v1.2.3 From 49494a736733e94b88e20b2b2fe9769c90862b5a Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Wed, 2 Oct 2013 13:01:56 +0200 Subject: Truncate file on File.open(file, "w") --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 8044874e9..43820a9de 100644 --- a/src/io.c +++ b/src/io.c @@ -29,7 +29,7 @@ mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) flags |= FMODE_READABLE; break; case 'w': - flags |= FMODE_WRITABLE | FMODE_CREATE; + flags |= FMODE_WRITABLE | FMODE_CREATE | FMODE_TRUNC; break; case 'a': flags |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE; -- cgit v1.2.3 From 005f01f2fc1b03a142ae04d4c94255fca15ddd33 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 3 Oct 2013 12:18:39 +0900 Subject: fix RSTRING_PTR usage. --- src/file.c | 59 +++++++++++++++++++++++++---------------------------------- test/file.rb | 17 +++++++++++------ 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/file.c b/src/file.c index 5c46aa965..ea45b2c0b 100644 --- a/src/file.c +++ b/src/file.c @@ -132,35 +132,29 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) static mrb_value mrb_file_dirname(mrb_state *mrb, mrb_value klass) { - char *cp, *dname; - mrb_int n; - mrb_value fname; + char *dname, *path; + mrb_value s; - mrb_get_args(mrb, "s", &cp, &n); - fname = mrb_str_new(mrb, cp, n); - - if ((dname = dirname(RSTRING_PTR(fname))) == NULL) { - mrb_sys_fail(mrb, "mrb_file_dirname failed."); + mrb_get_args(mrb, "S", &s); + path = mrb_str_to_cstr(mrb, s); + if ((dname = dirname(path)) == NULL) { + mrb_sys_fail(mrb, "dirname"); } - - return mrb_str_new(mrb, dname, strlen(dname)); + return mrb_str_new_cstr(mrb, dname); } static mrb_value mrb_file_basename(mrb_state *mrb, mrb_value klass) { - char *cp, *bname; - mrb_int n; - mrb_value fname; + char *bname, *path; + mrb_value s; - mrb_get_args(mrb, "s", &cp, &n); - fname = mrb_str_new(mrb, cp, n); - - if ((bname = basename(RSTRING_PTR(fname))) == NULL) { - mrb_sys_fail(mrb, "mrb_file_basename failed."); + mrb_get_args(mrb, "S", &s); + path = mrb_str_to_cstr(mrb, s); + if ((bname = basename(path)) == NULL) { + mrb_sys_fail(mrb, "basename"); } - - return mrb_str_new(mrb, bname, strlen(bname)); + return mrb_str_new_cstr(mrb, bname); } static mrb_value @@ -190,27 +184,26 @@ mrb_file_size(mrb_state *mrb, mrb_value klass) { char *cp; FILE *fp; - mrb_int n; mrb_int filesize; - mrb_value filename; + mrb_value s; + int saved_errno; - mrb_get_args(mrb, "s", &cp, &n); - filename = mrb_str_new(mrb, cp, n); - - fp = fopen(RSTRING_PTR(filename), "rb"); + mrb_get_args(mrb, "S", &s); + cp = mrb_str_to_cstr(mrb, s); + fp = fopen(cp, "rb"); if (fp == NULL) { - mrb_sys_fail(mrb, "mrb_file_size failed."); + mrb_sys_fail(mrb, "fopen"); return mrb_nil_value(); } - if (fseek(fp, 0, SEEK_END) != 0) { - mrb_sys_fail(mrb, "mrb_file_size failed."); + saved_errno = errno; + fclose(fp); + errno = saved_errno; + mrb_sys_fail(mrb, "fseek"); return mrb_nil_value(); } filesize = (mrb_int) ftell(fp); - fclose(fp); - return mrb_fixnum_value(filesize); } @@ -230,9 +223,7 @@ mrb_file__getwd(mrb_state *mrb, mrb_value klass) static int mrb_file_is_absolute_path(const char *path) { - if (path[0] == '/') - return 1; - return 0; + return (path[0] == '/'); } static mrb_value diff --git a/test/file.rb b/test/file.rb index 4b3458d1a..8865a30a9 100644 --- a/test/file.rb +++ b/test/file.rb @@ -30,14 +30,19 @@ assert('File#path', '15.2.21.4.2') do io.closed? end -assert('File.dirname') do - path = File.dirname("filename") - "." == path +assert('File.basename') do + assert_equal '/', File.basename('//') + assert_equal 'a', File.basename('/a/') + assert_equal 'b', File.basename('/a/b') + assert_equal 'b', File.basename('../a/b') end -assert('File.basename') do - name = File.basename("../somewhere/filename") - name == "filename" +assert('File.dirname') do + assert_equal '.', File.dirname('') + assert_equal '.', File.dirname('a') + assert_equal '/', File.dirname('/a') + assert_equal 'a', File.dirname('a/b') + assert_equal '/a', File.dirname('/a/b') end assert('File.extname') do -- cgit v1.2.3 From 93edd26b3e0d3d96f4589a8c7a382d12b911b52a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 9 Oct 2013 00:35:22 +0900 Subject: fix typo... --- test/file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/file.rb b/test/file.rb index 8865a30a9..1188fcc8f 100644 --- a/test/file.rb +++ b/test/file.rb @@ -58,7 +58,7 @@ assert('IO#flock') do f = File.open $mrbtest_io_rfname assert_equal(f.flock(File::LOCK_SH), 0) assert_equal(f.flock(File::LOCK_UN), 0) - assert_equal(f.flock(File::LOCK_EX | File::LOCK_UN), 0) + assert_equal(f.flock(File::LOCK_EX | File::LOCK_NB), 0) assert_equal(f.flock(File::LOCK_UN), 0) f.close true -- cgit v1.2.3 From 1e8097a4b895e673846be848feffdd0556041a65 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Sat, 16 Nov 2013 05:12:22 +0900 Subject: IO.sysopen raises an exception when open(2) fails. closes #6. --- mrblib/file.rb | 13 ------------- src/io.c | 2 ++ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index 5b6986985..243549cbb 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -14,20 +14,7 @@ class File < IO super(fd_or_path, mode) else @path = fd_or_path - - perm = 0666 unless perm.is_a? Fixnum fd = IO.sysopen(@path, mode, perm) - if fd < 0 && Object.const_defined?(:Errno) - begin - Errno.handle @path - rescue Errno::EMFILE - GC.run(true) - fd = IO.sysopen(@path, mode, perm) - Errno.handle if fd < 0 - end - elsif fd < 0 - raise NoFileError.new "no such file or directory" - end super(fd, mode) end end diff --git a/src/io.c b/src/io.c index 2438a1101..79f72d386 100644 --- a/src/io.c +++ b/src/io.c @@ -396,6 +396,8 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); fd = io_open(mrb, path, flags, perm); + if (fd == -1) + mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, path)); return mrb_fixnum_value(fd); } -- cgit v1.2.3 From e44da8a6cc587ba729bbc4ace0ca164f656207d8 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Sat, 16 Nov 2013 05:44:04 +0900 Subject: test for #6. --- test/io.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/io.rb b/test/io.rb index 77b6bc430..49a2a3f97 100644 --- a/test/io.rb +++ b/test/io.rb @@ -51,6 +51,18 @@ assert('IO.sysopen, IO#close, IO#closed?') do assert_equal true, io.closed?, "IO#closed? should return true" end +assert('IO.sysopen("/nonexistent")') do + if Object.const_defined? :Errno + eclass = Errno::ENOENT + else + eclass = RuntimeError + end + assert_raise eclass do + fd = IO.sysopen "/nonexistent" + IO.close fd + end +end + assert('IO.sysopen, IO#sysread') do fd = IO.sysopen $mrbtest_io_rfname io = IO.new fd -- cgit v1.2.3 From 87d878292d16bddad811a5cfd897ba27884bec8c Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Sat, 16 Nov 2013 16:04:31 +0900 Subject: Try GC when Too many open files (revert a part of 1e8097a). --- mrblib/file.rb | 7 ++++++- test/gc_filedes.sh | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 test/gc_filedes.sh diff --git a/mrblib/file.rb b/mrblib/file.rb index 243549cbb..048fbae80 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -14,7 +14,12 @@ class File < IO super(fd_or_path, mode) else @path = fd_or_path - fd = IO.sysopen(@path, mode, perm) + begin + fd = IO.sysopen(@path, mode, perm) + rescue Errno::EMFILE + GC.start + fd = IO.sysopen(@path, mode, perm) + end super(fd, mode) end end diff --git a/test/gc_filedes.sh b/test/gc_filedes.sh new file mode 100644 index 000000000..6e5d1bbf1 --- /dev/null +++ b/test/gc_filedes.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +ulimit -n 20 +mruby -e '100.times { File.open "'$0'" }' -- cgit v1.2.3 From 5a59fd3a5c83395847448db333c9df9d253a158c Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Mon, 2 Dec 2013 12:14:04 +0100 Subject: Fix for compilation under Win/MinGW --- include/mruby/ext/io.h | 6 +++++- src/file.c | 13 ++++++++++++- src/file_test.c | 2 ++ src/io.c | 9 +++++++-- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index a104d6d1f..209108a9d 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -16,7 +16,11 @@ extern "C" { #include #include -#include +#if !defined(_WIN32) || !defined(__MINGW32__) + #include +#else + #include +#endif #include #include #include diff --git a/src/file.c b/src/file.c index ea45b2c0b..1969b1411 100644 --- a/src/file.c +++ b/src/file.c @@ -17,7 +17,9 @@ #include #include #include +#ifndef _WIN32 #include +#endif #define FILE_SEPARATOR "/" @@ -229,6 +231,7 @@ mrb_file_is_absolute_path(const char *path) static mrb_value mrb_file__gethome(mrb_state *mrb, mrb_value klass) { +#ifndef _WIN32 mrb_value username; int argc; char *home; @@ -254,8 +257,13 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } } return mrb_str_new_cstr(mrb, home); +#else + + return mrb_nil_value(); +#endif } +#ifndef _WIN32 mrb_value mrb_file_flock(mrb_state *mrb, mrb_value self) { @@ -285,6 +293,7 @@ mrb_file_flock(mrb_state *mrb, mrb_value self) } return mrb_fixnum_value(0); } +#endif void mrb_init_file(mrb_state *mrb) @@ -306,8 +315,10 @@ mrb_init_file(mrb_state *mrb) mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, MRB_ARGS_NONE()); mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1)); + #ifndef _WIN32 mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1)); - + #endif + cnst = mrb_define_module_under(mrb, file, "Constants"); mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH)); mrb_define_const(mrb, cnst, "LOCK_EX", mrb_fixnum_value(LOCK_EX)); diff --git a/src/file_test.c b/src/file_test.c index 872f7aebc..309898a47 100644 --- a/src/file_test.c +++ b/src/file_test.c @@ -16,7 +16,9 @@ #include #include #include +#ifndef _WIN32 #include +#endif extern struct mrb_data_type mrb_io_type; diff --git a/src/io.c b/src/io.c index 79f72d386..c12f49a97 100644 --- a/src/io.c +++ b/src/io.c @@ -119,13 +119,14 @@ mrb_io_flags_to_modenum(mrb_state *mrb, int flags) } #ifdef O_BINARY if (flags & FMODE_BINMODE) { - modenum |= O_BINARY + modenum |= O_BINARY; } #endif return modenum; } +#ifndef _WIN32 static int mrb_proc_exec(const char *pname) { @@ -143,6 +144,7 @@ mrb_proc_exec(const char *pname) execl("/bin/sh", "sh", "-c", pname, (char *)NULL); return -1; } +#endif static void mrb_io_free(mrb_state *mrb, void *ptr) @@ -185,6 +187,7 @@ io_open(mrb_state *mrb, mrb_value path, int flags, int perm) #define NOFILE 64 #endif +#ifndef _WIN32 mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { @@ -295,6 +298,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) } return result; } +#endif mrb_value mrb_io_initialize(mrb_state *mrb, mrb_value io) @@ -746,8 +750,9 @@ mrb_init_io(mrb_state *mrb) MRB_SET_INSTANCE_TT(io, MRB_TT_DATA); mrb_include_module(mrb, io, mrb_class_get(mrb, "Enumerable")); /* 15.2.20.3 */ - +#ifndef _WIN32 mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); +#endif mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2)); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); -- cgit v1.2.3 From 23afaf02dc146346da823f85cea7a51263d0e2b7 Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Tue, 10 Dec 2013 14:34:26 +0100 Subject: Made compatible with VisualStudio --- include/mruby/ext/io.h | 14 +++++----- mrbgem.rake | 8 ++++++ src/file.c | 70 +++++++++++++++++++++++++++++++++++++++----------- src/file_test.c | 17 +++++++----- src/io.c | 10 ++++++++ 5 files changed, 90 insertions(+), 29 deletions(-) diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index 209108a9d..4a476e0d5 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -11,24 +11,24 @@ extern "C" { #include -#include #include #include #include -#if !defined(_WIN32) || !defined(__MINGW32__) - #include -#else +#if defined(_WIN32) || defined(_WIN64) #include +#else + #include + #include #endif #include #include #include struct mrb_io { - int fd; /* file descriptor */ - int fd2; /* file descriptor */ - int pid; /* child's pid (for pipes) */ + int fd; /* file descriptor */ + int fd2; /* file descriptor */ + int pid; /* child's pid (for pipes) */ }; struct mrb_io_type { diff --git a/mrbgem.rake b/mrbgem.rake index 029af4d26..77ad101af 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -3,4 +3,12 @@ MRuby::Gem::Specification.new('mruby-io') do |spec| spec.authors = 'Internet Initiative Japan Inc.' spec.cc.include_paths << "#{build.root}/src" + + case RUBY_PLATFORM + when /mingw|mswin/ + spec.linker.libraries += ['Ws2_32'] + #spec.cc.include_paths += ["C:/Windows/system/include"] + spec.linker.library_paths += ["C:/Windows/system"] + end + end diff --git a/src/file.c b/src/file.c index 1969b1411..ebc1e1392 100644 --- a/src/file.c +++ b/src/file.c @@ -10,15 +10,26 @@ #include "mruby/string.h" #include "error.h" -#include #include -#include #include #include #include -#include -#ifndef _WIN32 -#include +#if defined(_WIN32) || defined(_WIN64) + #define UNLINK _unlink + #define GETCWD _getcwd + #define CHMOD(a, b) 0 + #define MAXPATHLEN 1024 + #define PATH_MAX MAX_PATH + #define realpath(N,R) _fullpath((R),(N),_MAX_PATH) + #include +#else + #define UNLINK unlink + #define GETCWD getcwd + #define CHMOD(a, b) chmod(a,b) + #include + #include + #include + #include #endif #define FILE_SEPARATOR "/" @@ -44,16 +55,21 @@ extern mrb_value mrb_io_fileno(mrb_state *mrb, mrb_value io); mrb_value mrb_file_s_umask(mrb_state *mrb, mrb_value klass) { + int omask = 0; + #if defined(_WIN32) || defined(_WIN64) + /* nothing to do on windows */ + #else mrb_value *argv; int argc; + mrb_value mask; + mrb_get_args(mrb, "*", &argv, &argc); - int omask = 0; if (argc == 0) { omask = umask(0); umask(omask); } else if (argc == 1) { - mrb_value mask = argv[0]; + mask = argv[0]; if (!mrb_nil_p(mask) && !mrb_fixnum_p(mask)) { mask = mrb_check_convert_type(mrb, mask, MRB_TT_FIXNUM, "Fixnum", "to_int"); } @@ -64,6 +80,7 @@ mrb_file_s_umask(mrb_state *mrb, mrb_value klass) } else { mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 0..1)", argc); } + #endif return mrb_fixnum_value(omask); } @@ -72,15 +89,17 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) { mrb_value *argv; int n, i, argc; + const char *path; + mrb_value pathv; mrb_get_args(mrb, "*", &argv, &argc); for (i = 0, n = 0; i < argc; i++) { - mrb_value pathv = argv[i]; + pathv = argv[i]; if (mrb_type(pathv) != MRB_TT_STRING) { mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, pathv)); } - const char *path = mrb_string_value_cstr(mrb, &pathv);; - if (unlink(path) < 0) { + path = mrb_string_value_cstr(mrb, &pathv);; + if (UNLINK(path) < 0) { mrb_sys_fail(mrb, path); } else { n++; @@ -97,8 +116,8 @@ mrb_file_rename_internal(mrb_state *mrb, mrb_value from, mrb_value to) dst = mrb_string_value_cstr(mrb, &to); if (rename(src, dst) < 0) { - if (chmod(dst, 0666) == 0 && - unlink(dst) == 0 && + if (CHMOD(dst, 0666) == 0 && + UNLINK(dst) == 0 && rename(src, dst) == 0) return mrb_fixnum_value(0); mrb_sys_fail(mrb, "mrb_file_rename_internal failed."); @@ -134,29 +153,50 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) static mrb_value mrb_file_dirname(mrb_state *mrb, mrb_value klass) { + #if defined(_WIN32) || defined(_WIN64) + char dname[_MAX_DIR]; + char *path; + mrb_value s; + mrb_get_args(mrb, "S", &s); + path = mrb_str_to_cstr(mrb, s); + _splitpath((const char*)path, NULL, dname, NULL, NULL); + #else char *dname, *path; mrb_value s; - mrb_get_args(mrb, "S", &s); path = mrb_str_to_cstr(mrb, s); + if ((dname = dirname(path)) == NULL) { mrb_sys_fail(mrb, "dirname"); } + #endif return mrb_str_new_cstr(mrb, dname); } static mrb_value mrb_file_basename(mrb_state *mrb, mrb_value klass) { + #if defined(_WIN32) || defined(_WIN64) + char bname[_MAX_DIR]; + char extname[_MAX_EXT]; + char *path; + char buffer[_MAX_DIR + _MAX_EXT]; + mrb_value s; + mrb_get_args(mrb, "S", &s); + path = mrb_str_to_cstr(mrb, s); + _splitpath((const char*)path, NULL, NULL, bname, extname); + sprintf_s(buffer, _MAX_DIR + _MAX_EXT, "%s%s", bname, extname); + return mrb_str_new_cstr(mrb, buffer); + #else char *bname, *path; mrb_value s; - mrb_get_args(mrb, "S", &s); path = mrb_str_to_cstr(mrb, s); if ((bname = basename(path)) == NULL) { mrb_sys_fail(mrb, "basename"); } return mrb_str_new_cstr(mrb, bname); + #endif } static mrb_value @@ -215,7 +255,7 @@ mrb_file__getwd(mrb_state *mrb, mrb_value klass) mrb_value path; path = mrb_str_buf_new(mrb, MAXPATHLEN); - if (getcwd(RSTRING_PTR(path), MAXPATHLEN) == NULL) { + if (GETCWD(RSTRING_PTR(path), MAXPATHLEN) == NULL) { mrb_sys_fail(mrb, "getcwd(2)"); } mrb_str_resize(mrb, path, strlen(RSTRING_PTR(path))); diff --git a/src/file_test.c b/src/file_test.c index 309898a47..792440547 100644 --- a/src/file_test.c +++ b/src/file_test.c @@ -10,15 +10,18 @@ #include "mruby/string.h" #include "error.h" -#include -#include +#if defined(_WIN32) || defined(_WIN64) + #define LSTAT stat +#else + #define LSTAT lstat + #include + #include + #include + #include +#endif #include #include #include -#include -#ifndef _WIN32 -#include -#endif extern struct mrb_data_type mrb_io_type; @@ -47,7 +50,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); if (mrb_test(tmp)) { if (do_lstat) { - return lstat(mrb_str_to_cstr(mrb, obj), st); + return LSTAT(mrb_str_to_cstr(mrb, obj), st); } else { return stat(mrb_str_to_cstr(mrb, obj), st); } diff --git a/src/io.c b/src/io.c index c12f49a97..7164734c6 100644 --- a/src/io.c +++ b/src/io.c @@ -14,6 +14,16 @@ #include "mruby/ext/io.h" #include "error.h" +#if defined(_WIN32) || defined(_WIN64) + #include + #define open _open + #define close _close + #define read _read + #define write _write + #define lseek _lseek +#else +#endif + static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr); static int mrb_io_modenum_to_flags(mrb_state *mrb, int modenum); static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags); -- cgit v1.2.3 From 8cee36b1b58b7bc092d87b6c5482b654913ec4d4 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 13 Dec 2013 15:49:32 +0900 Subject: Catch Errno::ENFILE too. When system file descriptor table is full, errno is set to ENFILE instead of EMFILE. They are similar but different. --- mrblib/file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index 048fbae80..aaa88616f 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -16,7 +16,7 @@ class File < IO @path = fd_or_path begin fd = IO.sysopen(@path, mode, perm) - rescue Errno::EMFILE + rescue Errno::EMFILE, Errno::ENFILE GC.start fd = IO.sysopen(@path, mode, perm) end -- cgit v1.2.3 From a2af349959d7cc96302cbe49fabf50ec2633e4c4 Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Mon, 13 Jan 2014 17:29:57 +0100 Subject: Now the drive letter is returned as leading path element by File#dirname on Windows --- src/file.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/file.c b/src/file.c index ebc1e1392..7868eafaf 100644 --- a/src/file.c +++ b/src/file.c @@ -154,12 +154,15 @@ static mrb_value mrb_file_dirname(mrb_state *mrb, mrb_value klass) { #if defined(_WIN32) || defined(_WIN64) - char dname[_MAX_DIR]; + char dname[_MAX_DIR], vname[_MAX_DRIVE]; + char buffer[_MAX_DRIVE + _MAX_DIR]; char *path; mrb_value s; mrb_get_args(mrb, "S", &s); path = mrb_str_to_cstr(mrb, s); - _splitpath((const char*)path, NULL, dname, NULL, NULL); + _splitpath((const char*)path, vname, dname, NULL, NULL); + sprintf_s(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname); + return mrb_str_new_cstr(mrb, buffer); #else char *dname, *path; mrb_value s; -- cgit v1.2.3 From f10b73efa7674ca7fe361155b0733fde152c189f Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 3 Feb 2014 12:35:02 +0900 Subject: move license terms to the bottom. --- README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 51b6d1851..9cfdabbe8 100644 --- a/README.md +++ b/README.md @@ -4,28 +4,6 @@ mruby-io IO, File module for mruby -## License - -Copyright (c) 2013 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. - ## Implemented methods ### IO @@ -183,3 +161,25 @@ DEALINGS IN THE SOFTWARE. | File#size | | | | File#truncate | | | + +## License + +Copyright (c) 2013 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. -- cgit v1.2.3 From 526608c8a23f24c69a7474b78f24984785f81bad Mon Sep 17 00:00:00 2001 From: MATSUMOTO Ryosuke Date: Sat, 8 Feb 2014 17:38:41 +0900 Subject: Support mrb_module_ge --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 79f72d386..68a50a8d2 100644 --- a/src/io.c +++ b/src/io.c @@ -745,7 +745,7 @@ mrb_init_io(mrb_state *mrb) io = mrb_define_class(mrb, "IO", mrb->object_class); MRB_SET_INSTANCE_TT(io, MRB_TT_DATA); - mrb_include_module(mrb, io, mrb_class_get(mrb, "Enumerable")); /* 15.2.20.3 */ + mrb_include_module(mrb, io, mrb_module_get(mrb, "Enumerable")); /* 15.2.20.3 */ mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2)); -- cgit v1.2.3 From b74458a486042f4863fa6362057e25f0997694f5 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 10 Feb 2014 09:49:37 +0900 Subject: remove _bless trick. closes #8. --- mrblib/file.rb | 1 - src/io.c | 16 ---------------- 2 files changed, 17 deletions(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index aaa88616f..4087593a5 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -9,7 +9,6 @@ class File < IO attr_accessor :path def initialize(fd_or_path, mode = "r", perm = 0666) - self._bless if fd_or_path.kind_of? Fixnum super(fd_or_path, mode) else diff --git a/src/io.c b/src/io.c index 79f72d386..4453f2d6d 100644 --- a/src/io.c +++ b/src/io.c @@ -356,21 +356,6 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) } } -mrb_value -mrb_io_bless(mrb_state *mrb, mrb_value io) -{ - if (mrb_type(io) != MRB_TT_DATA) { - mrb_raise(mrb, E_TYPE_ERROR, "expected IO object"); - return mrb_nil_value(); - } - - DATA_TYPE(io) = &mrb_io_type; - DATA_PTR(io) = NULL; - DATA_PTR(io) = mrb_io_alloc(mrb); - - return io; -} - mrb_value mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass) { @@ -752,7 +737,6 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); - mrb_define_method(mrb, io, "_bless", mrb_io_bless, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ mrb_define_method(mrb, io, "sysread", mrb_io_sysread, MRB_ARGS_ANY()); mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From ee2859de6e8c95335db65746775737ad1bff35c8 Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Tue, 11 Feb 2014 14:54:30 +0100 Subject: Updated mrb_include_module call after mruby 1.0.0 --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 7164734c6..7b9b23b18 100644 --- a/src/io.c +++ b/src/io.c @@ -759,7 +759,7 @@ mrb_init_io(mrb_state *mrb) io = mrb_define_class(mrb, "IO", mrb->object_class); MRB_SET_INSTANCE_TT(io, MRB_TT_DATA); - mrb_include_module(mrb, io, mrb_class_get(mrb, "Enumerable")); /* 15.2.20.3 */ + mrb_include_module(mrb, io, mrb_module_get(mrb, "Enumerable")); /* 15.2.20.3 */ #ifndef _WIN32 mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); #endif -- cgit v1.2.3 From daa65c15dea5157a67876bd4b450971bd4832862 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 12 Feb 2014 16:33:34 +0900 Subject: add dummy IO#flush for better compatibility with CRuby. --- mrblib/io.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mrblib/io.rb b/mrblib/io.rb index ca687aee0..63a1bb714 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -41,6 +41,11 @@ class IO end end + def flush + # mruby-io always writes immediately (no output buffer). + self + end + def write(string) str = string.is_a?(String) ? string : string.to_s return str.size unless str.size > 0 -- cgit v1.2.3 From 7fd585bae174751e69b3a5e3a65e18eabaf7b1bd Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 14 Feb 2014 10:36:37 +0900 Subject: support older version. --- src/io.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/io.c b/src/io.c index fc343984a..78a04f8af 100644 --- a/src/io.c +++ b/src/io.c @@ -18,6 +18,14 @@ static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr); static int mrb_io_modenum_to_flags(mrb_state *mrb, int modenum); static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags); +#if MRUBY_RELEASE_NO < 10000 +static struct RClass * +mrb_module_get(mrb_state *mrb, const char *name) +{ + return mrb_class_get(mrb, name); +} +#endif + static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) { -- cgit v1.2.3 From d28f0421180b34f9f3fc3ae4e9b5c55ecae2e8f1 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Sat, 22 Feb 2014 20:45:07 +0900 Subject: compatibility support (mruby/mruby, iij/mruby and 1.0.0) - refs https://github.com/mruby/mruby/commit/36e234aa377d50d8ee425c7868e0651cf78e85cf --- src/file.c | 5 +++++ src/file_test.c | 5 +++++ src/io.c | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/file.c b/src/file.c index ea45b2c0b..eb4534168 100644 --- a/src/file.c +++ b/src/file.c @@ -8,7 +8,12 @@ #include "mruby/class.h" #include "mruby/data.h" #include "mruby/string.h" + +#if MRUBY_RELEASE_NO < 10000 #include "error.h" +#else +#include "mruby/error.h" +#endif #include #include diff --git a/src/file_test.c b/src/file_test.c index 872f7aebc..cb1f6229d 100644 --- a/src/file_test.c +++ b/src/file_test.c @@ -8,7 +8,12 @@ #include "mruby/class.h" #include "mruby/data.h" #include "mruby/string.h" + +#if MRUBY_RELEASE_NO < 10000 #include "error.h" +#else +#include "mruby/error.h" +#endif #include #include diff --git a/src/io.c b/src/io.c index 78a04f8af..e9b6c3d83 100644 --- a/src/io.c +++ b/src/io.c @@ -12,7 +12,12 @@ #include "mruby/string.h" #include "mruby/variable.h" #include "mruby/ext/io.h" + +#if MRUBY_RELEASE_NO < 10000 #include "error.h" +#else +#include "mruby/error.h" +#endif static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr); static int mrb_io_modenum_to_flags(mrb_state *mrb, int modenum); -- cgit v1.2.3 From 56a8c592dd02cc603a57669b37035f4b8054c587 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 25 Feb 2014 12:19:52 +0900 Subject: add IO.read --- README.md | 2 +- mrblib/io.rb | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- src/io.c | 15 +++++++++++++-- test/io.rb | 25 ++++++++++++++++++++++++- 4 files changed, 87 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9cfdabbe8..ee7d640eb 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ IO, File module for mruby | IO.foreach | | | | IO.pipe | | | | IO.popen | o | | -| IO.read | | | +| IO.read | o | | | IO.readlines | | | | IO.select | | | | IO.sysopen | o | | diff --git a/mrblib/io.rb b/mrblib/io.rb index 63a1bb714..4c69a4b99 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -41,6 +41,54 @@ class IO end end + + def self.read(path, length=nil, offset=nil, opt=nil) + if not opt.nil? # 4 arguments + offset ||= 0 + elsif not offset.nil? # 3 arguments + if offset.is_a? Hash + opt = offset + offset = 0 + else + opt = {} + end + elsif not length.nil? # 2 arguments + if length.is_a? Hash + opt = length + offset = 0 + length = nil + else + offset = 0 + opt = {} + end + else # only 1 argument + opt = {} + offset = 0 + length = nil + end + + str = "" + fd = -1 + io = nil + begin + if path[0] == "|" + io = IO.popen(path[1..-1], (opt[:mode] || "r")) + else + fd = IO.sysopen(path) + io = IO.open(fd, opt[:mode] || "r") + end + io.seek(offset) if offset > 0 + str = io.read(length) + ensure + if io + io.close + elsif fd != -1 + IO._sysclose(fd) + end + end + str + end + def flush # mruby-io always writes immediately (no output buffer). self @@ -130,7 +178,7 @@ class IO begin _read_buf rescue EOFError => e - str = nil if str.empty? + str = nil if str.empty? and (not length.nil?) and length != 0 break end diff --git a/src/io.c b/src/io.c index 78a04f8af..8c9de3667 100644 --- a/src/io.c +++ b/src/io.c @@ -3,7 +3,6 @@ */ #include "mruby.h" - #include "mruby/hash.h" #include "mruby/data.h" #include "mruby/khash.h" @@ -372,6 +371,17 @@ mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass) return mrb_io_initialize(mrb, io); } +mrb_value +mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass) +{ + mrb_int fd; + mrb_get_args(mrb, "i", &fd); + if (close(fd) == -1) { + mrb_sys_fail(mrb, "close"); + } + return mrb_fixnum_value(0); +} + mrb_value mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) { @@ -741,9 +751,10 @@ mrb_init_io(mrb_state *mrb) mrb_include_module(mrb, io, mrb_module_get(mrb, "Enumerable")); /* 15.2.20.3 */ mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, io, "_sysclose", mrb_io_s_sysclose, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2)); - mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ mrb_define_method(mrb, io, "sysread", mrb_io_sysread, MRB_ARGS_ANY()); diff --git a/test/io.rb b/test/io.rb index 49a2a3f97..02507a9d4 100644 --- a/test/io.rb +++ b/test/io.rb @@ -130,7 +130,7 @@ assert('IO#read') do io = IO.new fd assert_equal 'mruby', io.read(5) assert_equal $mrbtest_io_msg[5,100] + "\n", io.read - assert_equal nil, io.read + assert_equal "", io.read io.close io.closed? end @@ -251,6 +251,29 @@ assert('IO.popen') do io.closed? end +assert('IO.read') do + # empty file + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + io.close + assert_equal "", IO.read($mrbtest_io_wfname) + assert_equal nil, IO.read($mrbtest_io_wfname, 1) + + # one byte file + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + io.write "123" + io.close + assert_equal "123", IO.read($mrbtest_io_wfname) + assert_equal "", IO.read($mrbtest_io_wfname, 0) + assert_equal "1", IO.read($mrbtest_io_wfname, 1) + assert_equal "", IO.read($mrbtest_io_wfname, 0, 10) + assert_equal "23", IO.read($mrbtest_io_wfname, 2, 1) + assert_equal "23", IO.read($mrbtest_io_wfname, 10, 1) + assert_equal "", IO.read($mrbtest_io_wfname, nil, 10) + assert_equal nil, IO.read($mrbtest_io_wfname, 1, 10) +end + assert('IO#fileno') do fd = IO.sysopen $mrbtest_io_rfname io = IO.new fd -- cgit v1.2.3 From e8706d4ee7e9b04fc48f0f6ab66c32f90fb2edf0 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 25 Feb 2014 12:23:15 +0900 Subject: remove unused. --- src/io.c | 39 +-------------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/src/io.c b/src/io.c index 933078870..69b567db7 100644 --- a/src/io.c +++ b/src/io.c @@ -4,10 +4,9 @@ #include "mruby.h" #include "mruby/hash.h" -#include "mruby/data.h" -#include "mruby/khash.h" #include "mruby/array.h" #include "mruby/class.h" +#include "mruby/data.h" #include "mruby/string.h" #include "mruby/variable.h" #include "mruby/ext/io.h" @@ -19,7 +18,6 @@ #endif static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr); -static int mrb_io_modenum_to_flags(mrb_state *mrb, int modenum); static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags); #if MRUBY_RELEASE_NO < 10000 @@ -68,41 +66,6 @@ mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) return flags; } -static int -mrb_io_modenum_to_flags(mrb_state *mrb, int modenum) -{ - int flags = 0; - - switch (modenum & (O_RDONLY|O_WRONLY|O_RDWR)) { - case O_RDONLY: - flags = FMODE_READABLE; - break; - case O_WRONLY: - flags = FMODE_WRITABLE; - break; - case O_RDWR: - flags = FMODE_READWRITE; - break; - } - - if (modenum & O_APPEND) { - flags |= FMODE_APPEND; - } - if (modenum & O_TRUNC) { - flags |= FMODE_TRUNC; - } - if (modenum & O_CREAT) { - flags |= FMODE_CREATE; - } -#ifdef O_BINARY - if (modenum & O_BINARY) { - flags |= FMODE_BINMODE; - } -#endif - - return flags; -} - static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags) { -- cgit v1.2.3 From f7c054bd39f0809641ab474771f0f85a5282c72e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 25 Feb 2014 12:28:34 +0900 Subject: quiet compiler. --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 69b567db7..7047fdf88 100644 --- a/src/io.c +++ b/src/io.c @@ -506,7 +506,7 @@ mrb_io_pid(mrb_state *mrb, mrb_value io) static struct timeval time2timeval(mrb_state *mrb, mrb_value time) { - struct timeval t; + struct timeval t = { 0, 0 }; switch (mrb_type(time)) { case MRB_TT_FIXNUM: -- cgit v1.2.3 From 7ff049457f5c0c29ce3aec9414b98ae4226d2377 Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Tue, 4 Mar 2014 10:43:46 +0100 Subject: Added File.foreach method. Improved error management in File.new (Errno can be undefined) --- mrblib/file.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mrblib/file.rb b/mrblib/file.rb index 4087593a5..9a4333c64 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -12,9 +12,17 @@ class File < IO if fd_or_path.kind_of? Fixnum super(fd_or_path, mode) else + if Object.const_defined? :Errno + eclass = [Errno::ENOENT, Errno::ENFILE] + else + eclass = FileError + end + @path = fd_or_path begin fd = IO.sysopen(@path, mode, perm) + rescue RuntimeError => e + raise FileError, "Could not open file (#{e})" rescue Errno::EMFILE, Errno::ENFILE GC.start fd = IO.sysopen(@path, mode, perm) @@ -119,6 +127,16 @@ class File < IO end end + def self.foreach(file) + if block_given? + self.open(file) do |f| + f.each {|l| yield l} + end + else + return self.new(file) + end + end + def self.directory?(file) FileTest.directory?(file) end -- cgit v1.2.3 From 39bd240116b2980f90f9d8f350e18311959db54b Mon Sep 17 00:00:00 2001 From: Paolo Bosetti Date: Fri, 7 Mar 2014 16:47:18 +0100 Subject: Fixed bug in File.expand_path() on Windows (forever recursive loop) --- mrblib/file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index 9a4333c64..a4fcd3212 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -64,7 +64,7 @@ class File < IO def self.expand_path(path, default_dir = '.') def concat_path(path, base_path) - if path[0] == "/" + if path[0] == "/" || path[1] == ':' # Windows root! expanded_path = path elsif path[0] == "~" if (path[1] == "/" || path[1] == nil) -- cgit v1.2.3 From 719452b8d2c7201dcaca0c2264051783bbd89c67 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 14 Mar 2014 10:47:54 +0900 Subject: remove unsed. --- mrblib/file.rb | 6 ------ src/io.c | 35 ----------------------------------- 2 files changed, 41 deletions(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index a4fcd3212..5a2716a66 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -12,12 +12,6 @@ class File < IO if fd_or_path.kind_of? Fixnum super(fd_or_path, mode) else - if Object.const_defined? :Errno - eclass = [Errno::ENOENT, Errno::ENFILE] - else - eclass = FileError - end - @path = fd_or_path begin fd = IO.sysopen(@path, mode, perm) diff --git a/src/io.c b/src/io.c index c8318e4a1..0b39031ee 100644 --- a/src/io.c +++ b/src/io.c @@ -76,41 +76,6 @@ mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) return flags; } -static int -mrb_io_modenum_to_flags(mrb_state *mrb, int modenum) -{ - int flags = 0; - - switch (modenum & (O_RDONLY|O_WRONLY|O_RDWR)) { - case O_RDONLY: - flags = FMODE_READABLE; - break; - case O_WRONLY: - flags = FMODE_WRITABLE; - break; - case O_RDWR: - flags = FMODE_READWRITE; - break; - } - - if (modenum & O_APPEND) { - flags |= FMODE_APPEND; - } - if (modenum & O_TRUNC) { - flags |= FMODE_TRUNC; - } - if (modenum & O_CREAT) { - flags |= FMODE_CREATE; - } -#ifdef O_BINARY - if (modenum & O_BINARY) { - flags |= FMODE_BINMODE; - } -#endif - - return flags; -} - static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags) { -- cgit v1.2.3 From ab9dcc766e6ea82f88ed9f90a5cf3ba4096ee778 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 26 Mar 2014 17:22:57 +0900 Subject: IO.close should be IO._sysclose. closes #13. --- test/io.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/io.rb b/test/io.rb index 02507a9d4..de6c52d07 100644 --- a/test/io.rb +++ b/test/io.rb @@ -59,7 +59,7 @@ assert('IO.sysopen("/nonexistent")') do end assert_raise eclass do fd = IO.sysopen "/nonexistent" - IO.close fd + IO._sysclose fd end end -- cgit v1.2.3 From eda9d1a8fc299979239b8aeb0382abf51b3fc363 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Wed, 26 Mar 2014 22:09:10 +0900 Subject: nonexistent test fixes (for travis-ci) --- test/io.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/io.rb b/test/io.rb index de6c52d07..99f236fb4 100644 --- a/test/io.rb +++ b/test/io.rb @@ -51,14 +51,14 @@ assert('IO.sysopen, IO#close, IO#closed?') do assert_equal true, io.closed?, "IO#closed? should return true" end -assert('IO.sysopen("/nonexistent")') do +assert('IO.sysopen("./nonexistent")') do if Object.const_defined? :Errno eclass = Errno::ENOENT else eclass = RuntimeError end assert_raise eclass do - fd = IO.sysopen "/nonexistent" + fd = IO.sysopen "./nonexistent" IO._sysclose fd end end -- cgit v1.2.3 From 1094bbfff81d947fd0271e0af03b73b3a351f6ee Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Apr 2014 11:25:04 +0900 Subject: 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" -- cgit v1.2.3 From 083cd9ca8cda20a4a268d5ed2d95d738ab4f4460 Mon Sep 17 00:00:00 2001 From: Akira Yumiyama Date: Fri, 4 Apr 2014 11:31:33 +0900 Subject: 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" -- cgit v1.2.3 From 706ef1337a8fccea8d75a10d73701e536d4f79b1 Mon Sep 17 00:00:00 2001 From: Masaki Muranaka Date: Sat, 5 Apr 2014 10:36:30 +0900 Subject: Don't ignore the return value of symlink(). --- test/mruby_io_test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index 6a3b20f62..36e56b87c 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -112,7 +112,9 @@ static mrb_value mrb_io_test_file_setup(mrb_state *mrb, mrb_value self) { mrb_value ary = mrb_io_test_io_setup(mrb, self); - symlink("/usr/bin", "test-bin"); + if (symlink("/usr/bin", "test-bin") == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link"); + } return ary; } -- cgit v1.2.3 From cd168c6f32180ef927becc65a1e40a7cde6703db Mon Sep 17 00:00:00 2001 From: Julien Ammous Date: Thu, 10 Apr 2014 19:26:55 +0200 Subject: solaris does not have flock --- src/file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/file.c b/src/file.c index 324cc81f2..930833370 100644 --- a/src/file.c +++ b/src/file.c @@ -315,6 +315,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) mrb_value mrb_file_flock(mrb_state *mrb, mrb_value self) { +#if !defined(sun) mrb_int operation; int fd; @@ -339,6 +340,7 @@ mrb_file_flock(mrb_state *mrb, mrb_value self) break; } } +#endif return mrb_fixnum_value(0); } #endif -- cgit v1.2.3 From 810e37b1c3202eef6164933234d137d8d095e034 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 17 Apr 2014 15:45:31 +0900 Subject: return value of syswrite may be less than length of given string. --- mrblib/io.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 4c69a4b99..249488ac4 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -99,7 +99,7 @@ class IO return str.size unless str.size > 0 len = syswrite(str) - if str.size == len + if len != -1 @pos += len return len end -- cgit v1.2.3 From 87ce12dfe3f096128cde7c835cb8099342d78303 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 17 Apr 2014 15:53:51 +0900 Subject: io.write("") -> 0 --- test/io.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/io.rb b/test/io.rb index 99f236fb4..0db0e9e75 100644 --- a/test/io.rb +++ b/test/io.rb @@ -33,6 +33,13 @@ assert('IO.open', '15.2.20.4.1') do true end +assert('IO#write', '15.2.20.5.20') do + io = IO.open(IO.sysopen($mrbtest_io_wfname)) + assert_equal 0, io.write("") + io.close + true +end + assert('IO.new') do IO.new(0) end -- cgit v1.2.3 From 10be4cbb2cc59b0f0090d9500ede792aa5084d0e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 17 Apr 2014 15:56:11 +0900 Subject: file.c does not depend on mruby/ext/io.h. --- src/file.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/file.c b/src/file.c index 930833370..fa7839dca 100644 --- a/src/file.c +++ b/src/file.c @@ -4,7 +4,6 @@ #include "mruby.h" -#include "mruby/ext/io.h" #include "mruby/class.h" #include "mruby/data.h" #include "mruby/string.h" @@ -15,8 +14,14 @@ #include "mruby/error.h" #endif +#include +#include + #include #include +#include + +#include #include #include #if defined(_WIN32) || defined(_WIN64) -- cgit v1.2.3 From ba9cb1f7579903459aae8621139fefbba04a3f9c Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 17 Apr 2014 16:07:12 +0900 Subject: "struct mrb_io_type" is not used at all. --- include/mruby/ext/io.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index 4a476e0d5..3f6b57997 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -31,11 +31,6 @@ struct mrb_io { int pid; /* child's pid (for pipes) */ }; -struct mrb_io_type { - const char *struct_name; - void (*dfree)(mrb_state *mrb, void *); -}; - #define FMODE_READABLE 0x00000001 #define FMODE_WRITABLE 0x00000002 #define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE) -- cgit v1.2.3 From 9f5ff9ddecc89e7601b1257fe4cef447b77850c6 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 17 Apr 2014 16:12:51 +0900 Subject: remove unused constants. --- include/mruby/ext/io.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index 3f6b57997..61da9195a 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -36,15 +36,9 @@ struct mrb_io { #define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE) #define FMODE_BINMODE 0x00000004 #define FMODE_SYNC 0x00000008 -#define FMODE_TTY 0x00000010 -#define FMODE_DUPLEX 0x00000020 #define FMODE_APPEND 0x00000040 #define FMODE_CREATE 0x00000080 -#define FMODE_WSPLIT 0x00000200 -#define FMODE_WSPLIT_INITIALIZED 0x00000400 #define FMODE_TRUNC 0x00000800 -#define FMODE_TEXTMODE 0x00001000 -#define FMODE_SETENC_BY_BOM 0x00100000 #define E_IO_ERROR (mrb_class_get(mrb, "IOError")) #define E_EOF_ERROR (mrb_class_get(mrb, "EOFError")) -- cgit v1.2.3 From a3e1e535dc2809f7c0848e40d038f3cacadb4b66 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 17 Apr 2014 16:13:18 +0900 Subject: function declarations should be in a header file. --- include/mruby/ext/io.h | 1 + src/file.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index 61da9195a..25ca37d49 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -46,6 +46,7 @@ struct mrb_io { mrb_value mrb_open_file(mrb_state *mrb, int argc, mrb_value *argv, mrb_value io); void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise); mrb_value mrb_file_exist(mrb_state *mrb, mrb_value fname); +mrb_value mrb_io_fileno(mrb_state *mrb, mrb_value io); #if defined(__cplusplus) } /* extern "C" { */ diff --git a/src/file.c b/src/file.c index fa7839dca..24a95f49a 100644 --- a/src/file.c +++ b/src/file.c @@ -59,8 +59,6 @@ #define STAT(p, s) stat(p, s) -extern mrb_value mrb_io_fileno(mrb_state *mrb, mrb_value io); - mrb_value mrb_file_s_umask(mrb_state *mrb, mrb_value klass) -- cgit v1.2.3 From a11780f4f1197aa2082804f80630a775dc26153d Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 17 Apr 2014 16:18:26 +0900 Subject: file.c depends on mruby/ext/io.h now. --- src/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/file.c b/src/file.c index 24a95f49a..b43f092fa 100644 --- a/src/file.c +++ b/src/file.c @@ -4,6 +4,7 @@ #include "mruby.h" +#include "mruby/ext/io.h" #include "mruby/class.h" #include "mruby/data.h" #include "mruby/string.h" -- cgit v1.2.3 From 1c4f46f3244bf4b4b3e8acf55348e6104a2ace4f Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 17 Apr 2014 16:29:27 +0900 Subject: remove standard header files from io.h. --- include/mruby/ext/io.h | 19 ------------------- src/file_test.c | 17 +++++++++++++---- src/io.c | 18 ++++++++++++++++-- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index 25ca37d49..8cf2e90b0 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -9,22 +9,6 @@ extern "C" { #endif -#include - -#include - -#include -#include -#if defined(_WIN32) || defined(_WIN64) - #include -#else - #include - #include -#endif -#include -#include -#include - struct mrb_io { int fd; /* file descriptor */ int fd2; /* file descriptor */ @@ -43,9 +27,6 @@ struct mrb_io { #define E_IO_ERROR (mrb_class_get(mrb, "IOError")) #define E_EOF_ERROR (mrb_class_get(mrb, "EOFError")) -mrb_value mrb_open_file(mrb_state *mrb, int argc, mrb_value *argv, mrb_value io); -void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise); -mrb_value mrb_file_exist(mrb_state *mrb, mrb_value fname); mrb_value mrb_io_fileno(mrb_state *mrb, mrb_value io); #if defined(__cplusplus) diff --git a/src/file_test.c b/src/file_test.c index 37b139c78..d3dfb15ba 100644 --- a/src/file_test.c +++ b/src/file_test.c @@ -3,11 +3,10 @@ */ #include "mruby.h" - -#include "mruby/ext/io.h" #include "mruby/class.h" #include "mruby/data.h" #include "mruby/string.h" +#include "mruby/ext/io.h" #if MRUBY_RELEASE_NO < 10000 #include "error.h" @@ -15,16 +14,26 @@ #include "mruby/error.h" #endif +#include +#include + #if defined(_WIN32) || defined(_WIN64) #define LSTAT stat + #include #else #define LSTAT lstat #include + #include + #include #include #include - #include + #include #endif -#include + +#include + +#include +#include #include #include diff --git a/src/io.c b/src/io.c index 0b39031ee..1692e76a5 100644 --- a/src/io.c +++ b/src/io.c @@ -3,10 +3,10 @@ */ #include "mruby.h" -#include "mruby/hash.h" #include "mruby/array.h" #include "mruby/class.h" #include "mruby/data.h" +#include "mruby/hash.h" #include "mruby/string.h" #include "mruby/variable.h" #include "mruby/ext/io.h" @@ -17,7 +17,11 @@ #include "mruby/error.h" #endif +#include +#include + #if defined(_WIN32) || defined(_WIN64) + #include #include #define open _open #define close _close @@ -25,10 +29,20 @@ #define write _write #define lseek _lseek #else + #include + #include #endif +#include + +#include +#include +#include + + static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr); static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags); +static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise); #if MRUBY_RELEASE_NO < 10000 static struct RClass * @@ -318,7 +332,7 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) return io; } -void +static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) { int n = 0; -- cgit v1.2.3 From 36045ea96fa499681a5773c1148a7ddc6715face Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 18 Apr 2014 11:20:55 +0900 Subject: IO#syswrite should raise an error if it's not opened for writing. --- include/mruby/ext/io.h | 5 +++-- src/io.c | 32 +++++++++++++++++++++----------- test/io.rb | 7 ++++++- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index 8cf2e90b0..7d61ba267 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -10,9 +10,10 @@ extern "C" { #endif struct mrb_io { - int fd; /* file descriptor */ - int fd2; /* file descriptor */ + int fd; /* file descriptor, or -1 */ + int fd2; /* file descriptor to write if it's different from fd, or -1 */ int pid; /* child's pid (for pipes) */ + unsigned int writable:1; }; #define FMODE_READABLE 0x00000001 diff --git a/src/io.c b/src/io.c index 1692e76a5..a61a2e0da 100644 --- a/src/io.c +++ b/src/io.c @@ -157,16 +157,16 @@ mrb_io_free(mrb_state *mrb, void *ptr) struct mrb_data_type mrb_io_type = { "IO", mrb_io_free }; -static struct mrb_io* +static struct mrb_io * mrb_io_alloc(mrb_state *mrb) { struct mrb_io *fptr; fptr = (struct mrb_io *)mrb_malloc(mrb, sizeof(struct mrb_io)); - fptr->fd = -1; + fptr->fd = -1; fptr->fd2 = -1; fptr->pid = 0; - + fptr->writable = 0; return fptr; } @@ -272,9 +272,10 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr = mrb_io_alloc(mrb); - fptr->fd = fd; + fptr->fd = fd; fptr->fd2 = write_fd; fptr->pid = pid; + fptr->writable = ((flags & FMODE_WRITABLE) != 0); DATA_TYPE(io) = &mrb_io_type; DATA_PTR(io) = fptr; @@ -305,9 +306,7 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) struct mrb_io *fptr; mrb_int fd; mrb_value mode, opt; - - DATA_TYPE(io) = &mrb_io_type; - DATA_PTR(io) = NULL; + int flags; mode = opt = mrb_nil_value(); @@ -319,16 +318,23 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) opt = mrb_hash_new(mrb); } + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr = DATA_PTR(io); - if (fptr == NULL) { - fptr = mrb_io_alloc(mrb); + if (fptr != NULL) { + fptr_finalize(mrb, fptr, 0); + mrb_free(mrb, fptr); } - fptr->fd = fd; + fptr = mrb_io_alloc(mrb); + + DATA_TYPE(io) = &mrb_io_type; DATA_PTR(io) = fptr; + fptr->fd = fd; + fptr->writable = ((flags & FMODE_WRITABLE) != 0); return io; } @@ -473,6 +479,11 @@ mrb_io_syswrite(mrb_state *mrb, mrb_value io) mrb_value str, buf; int fd, length; + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + if (! fptr->writable) { + mrb_raise(mrb, E_IO_ERROR, "not opened for writing"); + } + mrb_get_args(mrb, "S", &str); if (mrb_type(str) != MRB_TT_STRING) { buf = mrb_funcall(mrb, str, "to_s", 0); @@ -480,7 +491,6 @@ mrb_io_syswrite(mrb_state *mrb, mrb_value io) buf = str; } - fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); if (fptr->fd2 == -1) { fd = fptr->fd; } else { diff --git a/test/io.rb b/test/io.rb index 0db0e9e75..eb605ef31 100644 --- a/test/io.rb +++ b/test/io.rb @@ -92,7 +92,12 @@ assert('IO.sysopen, IO#syswrite') do len = io.syswrite(str) assert_equal str.size, len io.close - io.closed? + + io = IO.new(IO.sysopen($mrbtest_io_rfname), "r") + assert_raise(IOError) { io.syswrite("a") } + io.close + + true end assert('IO#_read_buf') do -- cgit v1.2.3 From 7d7a549a4fb546ae3fc5b9a3dca8aae9159edaff Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 18 Apr 2014 11:32:38 +0900 Subject: remove io_open(). --- src/io.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/io.c b/src/io.c index a61a2e0da..95f379263 100644 --- a/src/io.c +++ b/src/io.c @@ -170,18 +170,6 @@ mrb_io_alloc(mrb_state *mrb) return fptr; } -static int -io_open(mrb_state *mrb, mrb_value path, int flags, int perm) -{ - const char *pat; - int modenum; - - pat = mrb_string_value_cstr(mrb, &path); - modenum = mrb_io_flags_to_modenum(mrb, flags); - - return open(pat, modenum, perm); -} - #ifndef NOFILE #define NOFILE 64 #endif @@ -390,6 +378,8 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) mrb_value path = mrb_nil_value(); mrb_value mode = mrb_nil_value(); mrb_int fd, flags, perm = -1; + const char *pat; + int modenum; mrb_get_args(mrb, "S|Si", &path, &mode, &perm); if (mrb_nil_p(mode)) { @@ -399,10 +389,14 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) perm = 0666; } + pat = mrb_string_value_cstr(mrb, &path); flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); - fd = io_open(mrb, path, flags, perm); - if (fd == -1) - mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, path)); + modenum = mrb_io_flags_to_modenum(mrb, flags); + + fd = open(pat, modenum, perm); + if (fd == -1) { + mrb_sys_fail(mrb, pat); + } return mrb_fixnum_value(fd); } -- cgit v1.2.3 From 99c67749ff38ff5da1bc1d38edf07323f3cd0df4 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 21 Apr 2014 09:06:46 +0900 Subject: remove return statements after mrb_raise(). --- src/io.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/io.c b/src/io.c index 95f379263..9b51ef780 100644 --- a/src/io.c +++ b/src/io.c @@ -428,12 +428,10 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) buf = mrb_str_new_cstr(mrb, ""); } else { mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File"); - return mrb_nil_value(); } break; case -1: /* Error */ mrb_raise(mrb, E_IO_ERROR, "sysread failed"); - return mrb_nil_value(); break; default: if (RSTRING_LEN(buf) != ret) { @@ -460,7 +458,6 @@ mrb_io_sysseek(mrb_state *mrb, mrb_value io) pos = lseek(fptr->fd, offset, whence); if (pos < 0) { mrb_raise(mrb, E_IO_ERROR, "sysseek faield"); - return mrb_nil_value(); } return mrb_fixnum_value(pos); @@ -502,9 +499,7 @@ mrb_io_close(mrb_state *mrb, mrb_value io) fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); if (fptr && fptr->fd < 0) { mrb_raise(mrb, E_IO_ERROR, "closed stream."); - return mrb_nil_value(); } - fptr_finalize(mrb, fptr, FALSE); return mrb_nil_value(); } @@ -514,7 +509,6 @@ mrb_io_closed(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); - if (fptr->fd >= 0) { return mrb_false_value(); } @@ -589,7 +583,6 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass) if (argc < 1 || argc > 4) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 1..4)", argc); - return mrb_nil_value(); } timeout = mrb_nil_value(); -- cgit v1.2.3 From e5f30f83ce5f5a11c77990718b323f4718a3a03a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 21 Apr 2014 10:01:49 +0900 Subject: IO#flush should raise an exception if it is closed. --- mrblib/io.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/mrblib/io.rb b/mrblib/io.rb index 249488ac4..cd8c801d2 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -91,6 +91,7 @@ class IO def flush # mruby-io always writes immediately (no output buffer). + raise IOError, "closed stream" if self.closed? self end -- cgit v1.2.3 From c46cb1b5eb1f92a23500bf877c10cd65e7c43e45 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 21 Apr 2014 10:02:25 +0900 Subject: more tests. --- test/file.rb | 4 +- test/file_test.rb | 4 +- test/io.rb | 156 +++++++++++++++++++++++++++++++-------------------- test/mruby_io_test.c | 4 +- 4 files changed, 102 insertions(+), 66 deletions(-) diff --git a/test/file.rb b/test/file.rb index 1188fcc8f..c8df85e89 100644 --- a/test/file.rb +++ b/test/file.rb @@ -23,7 +23,7 @@ end assert('File#path', '15.2.21.4.2') do io = File.open($mrbtest_io_rfname, "r") - assert_equal $mrbtest_io_msg + "\n", io.read + assert_equal $mrbtest_io_msg, io.read assert_equal $mrbtest_io_rfname, io.path io.close assert_equal $mrbtest_io_rfname, io.path @@ -66,7 +66,7 @@ end assert('File.size') do - File.size($mrbtest_io_rfname) == $mrbtest_io_msg.size + 1 and + File.size($mrbtest_io_rfname) == $mrbtest_io_msg.size and File.size($mrbtest_io_wfname) == 0 end diff --git a/test/file_test.rb b/test/file_test.rb index dc92505ca..1fe6a8fd8 100644 --- a/test/file_test.rb +++ b/test/file_test.rb @@ -34,13 +34,13 @@ assert("FileTest.pipe?") do end assert("FileTest.size?") do - assert_equal $mrbtest_io_msg.size+1, FileTest.size?($mrbtest_io_rfname) + assert_equal $mrbtest_io_msg.size, FileTest.size?($mrbtest_io_rfname) assert_equal nil, FileTest.size?($mrbtest_io_wfname) assert_equal nil, FileTest.size?("not-exist-test-target-file") fp1 = File.open($mrbtest_io_rfname) fp2 = File.open($mrbtest_io_wfname) - assert_equal $mrbtest_io_msg.size+1, FileTest.size?(fp1) + assert_equal $mrbtest_io_msg.size, FileTest.size?(fp1) assert_equal nil, FileTest.size?(fp2) fp1.close fp2.close diff --git a/test/io.rb b/test/io.rb index eb605ef31..0ec0ef725 100644 --- a/test/io.rb +++ b/test/io.rb @@ -22,17 +22,106 @@ assert('IO.open', '15.2.20.4.1') do assert_equal Fixnum, fd.class io = IO.open fd assert_equal IO, io.class - assert_equal $mrbtest_io_msg+"\n", io.read + assert_equal $mrbtest_io_msg, io.read io.close fd = IO.sysopen $mrbtest_io_rfname IO.open(fd) do |io| - assert_equal $mrbtest_io_msg+"\n", io.read + assert_equal $mrbtest_io_msg, io.read end true end +assert('IO#close', '15.2.20.5.1') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + assert_nil io.close +end + +assert('IO#closed?', '15.2.20.5.2') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + assert_false io.closed? + io.close + assert_true io.closed? +end + +#assert('IO#each', '15.2.20.5.3') do +#assert('IO#each_byte', '15.2.20.5.4') do +#assert('IO#each_line', '15.2.20.5.5') do + +assert('IO#eof?', '15.2.20.5.6') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + $mrbtest_io_msg.each_char { |ch| + # XXX + #assert_false io.eof? + io.getc + } + assert_true io.eof? + io.close + true +end + +assert('IO#flush', '15.2.20.5.7') do + # Note: mruby-io does not have any buffer to be flushed now. + io = IO.new(IO.sysopen($mrbtest_io_wfname)) + assert_equal io, io.flush + io.close + assert_raise(IOError) do + io.flush + end +end + +assert('IO#getc', '15.2.20.5.8') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + $mrbtest_io_msg.each_char { |ch| + assert_equal ch, io.getc + } + assert_equal nil, io.getc + io.close + true +end + +#assert('IO#gets', '15.2.20.5.9') do +#assert('IO#initialize_copy', '15.2.20.5.10') do +#assert('IO#print', '15.2.20.5.11') do +#assert('IO#putc', '15.2.20.5.12') do +#assert('IO#puts', '15.2.20.5.13') do + +assert('IO#read', '15.2.20.5.14') do + IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| + assert_raise(ArgumentError) { io.read(-5) } + assert_raise(TypeError) { io.read("str") } + + len = $mrbtest_io_msg.length + assert_equal 'mruby', io.read(5) + assert_equal $mrbtest_io_msg[5,len], io.read(len) + + assert_equal "", io.read + assert_nil io.read(1) + end + + IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| + assert_equal $mrbtest_io_msg, io.read + end +end + +assert('IO#readchar', '15.2.20.5.15') do + # almost same as IO#getc + IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| + $mrbtest_io_msg.each_char { |ch| + assert_equal ch, io.readchar + } + assert_raise(EOFError) do + io.readchar + end + end +end + +#assert('IO#readline', '15.2.20.5.16') do +#assert('IO#readlines', '15.2.20.5.17') do +#assert('IO#sync', '15.2.20.5.18') do +#assert('IO#sync=', '15.2.20.5.19') do + assert('IO#write', '15.2.20.5.20') do io = IO.open(IO.sysopen($mrbtest_io_wfname)) assert_equal 0, io.write("") @@ -48,16 +137,6 @@ assert('IO gc check') do 100.times { IO.new(0) } end -assert('IO.sysopen, IO#close, IO#closed?') do - fd = IO.sysopen $mrbtest_io_rfname - assert_equal Fixnum, fd.class - io = IO.new fd - assert_equal IO, io.class - assert_equal false, io.closed?, "IO not closed" - assert_equal nil, io.close, "IO#close should return nil" - assert_equal true, io.closed?, "IO#closed? should return true" -end - assert('IO.sysopen("./nonexistent")') do if Object.const_defined? :Errno eclass = Errno::ENOENT @@ -106,14 +185,14 @@ assert('IO#_read_buf') do def io._buf @buf end - msg_len = $mrbtest_io_msg.size + 1 + msg_len = $mrbtest_io_msg.size assert_equal '', io._buf - assert_equal $mrbtest_io_msg + "\n", io._read_buf - assert_equal $mrbtest_io_msg + "\n", io._buf + assert_equal $mrbtest_io_msg, io._read_buf + assert_equal $mrbtest_io_msg, io._buf assert_equal 'mruby', io.read(5) assert_equal 5, io.pos assert_equal msg_len - 5, io._buf.size - assert_equal $mrbtest_io_msg[5,100] + "\n", io.read + assert_equal $mrbtest_io_msg[5,100], io.read assert_equal 0, io._buf.size assert_raise EOFError do io._read_buf @@ -124,48 +203,6 @@ assert('IO#_read_buf') do io.closed? end -assert('IO#read argument check') do - fd = IO.sysopen $mrbtest_io_rfname - io = IO.new fd - assert_raise TypeError do - io.read("str") - end - assert_raise ArgumentError do - io.read(-5) - end - io.close - io.closed? -end - -assert('IO#read') do - fd = IO.sysopen $mrbtest_io_rfname - io = IO.new fd - assert_equal 'mruby', io.read(5) - assert_equal $mrbtest_io_msg[5,100] + "\n", io.read - assert_equal "", io.read - io.close - io.closed? -end - -assert('IO#readchar, IO#getc') do - fd = IO.sysopen $mrbtest_io_rfname - io = IO.new fd - def io._buf - @buf - end - assert_equal 'm', io.readchar - assert_equal 1, io.pos - assert_equal 'r', io.getc - assert_equal 2, io.pos - io.gets - assert_raise EOFError do - io.readchar - end - assert_equal nil, io.getc - io.close - io.closed? -end - assert('IO#pos=, IO#seek') do fd = IO.sysopen $mrbtest_io_rfname io = IO.new fd @@ -180,13 +217,12 @@ assert('IO#pos=, IO#seek') do io.closed? end - assert('IO#gets') do fd = IO.sysopen $mrbtest_io_rfname io = IO.new fd # gets without arguments - assert_equal $mrbtest_io_msg + "\n", io.gets, "gets without arguments" + assert_equal $mrbtest_io_msg, io.gets, "gets without arguments" assert_equal nil, io.gets, "gets returns nil, when EOF" # gets with limit diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index 36e56b87c..f58f9ff8c 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -18,7 +18,7 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) char wfname[] = "tmp.mruby-io-test.XXXXXXXX"; char symlinkname[] = "tmp.mruby-io-test.XXXXXXXX"; char socketname[] = "tmp.mruby-io-test.XXXXXXXX"; - char msg[] = "mruby io test"; + char msg[] = "mruby io test\n"; mode_t mask; int fd0, fd1, fd2, fd3; FILE *fp; @@ -46,7 +46,7 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file"); return mrb_nil_value(); } - fprintf(fp, "%s\n", msg); + fputs(msg, fp); fclose(fp); fp = fopen(wfname, "w"); -- cgit v1.2.3 From 9c00de59ceb3cf7e1a285745fa3f3c93f16cd9ec Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 21 Apr 2014 10:24:59 +0900 Subject: IO.for_fd can be written in Ruby. --- mrblib/io.rb | 4 ++++ src/io.c | 9 --------- test/io.rb | 12 +++++++++++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index cd8c801d2..902d847d2 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -11,6 +11,10 @@ class IO BUF_SIZE = 4096 + def self.for_fd *args + self.new(*args) + end + def self.open(*args, &block) io = self.new(*args) diff --git a/src/io.c b/src/io.c index 9b51ef780..cbaf523d8 100644 --- a/src/io.c +++ b/src/io.c @@ -353,14 +353,6 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) } } -mrb_value -mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass) -{ - mrb_value io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); - - return mrb_io_initialize(mrb, io); -} - mrb_value mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass) { @@ -746,7 +738,6 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "_sysclose", mrb_io_s_sysclose, MRB_ARGS_REQ(1)); #endif - mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(2)); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); diff --git a/test/io.rb b/test/io.rb index 0ec0ef725..b5b952425 100644 --- a/test/io.rb +++ b/test/io.rb @@ -129,8 +129,18 @@ assert('IO#write', '15.2.20.5.20') do true end +assert('IO.for_fd') do + fd = IO.sysopen($mrbtest_io_rfname) + io = IO.for_fd(fd) + assert_equal $mrbtest_io_msg, io.read + io.close + true +end + assert('IO.new') do - IO.new(0) + io = IO.new(0) + io.close + true end assert('IO gc check') do -- cgit v1.2.3 From 5aeb99ad49794d0bca845872daf72e641750d8d9 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Mon, 21 Apr 2014 11:14:40 +0900 Subject: fix mrb_raisef usage. --- src/file.c | 85 ++++++++++++++++---------------------------------------------- src/io.c | 9 +++---- 2 files changed, 25 insertions(+), 69 deletions(-) diff --git a/src/file.c b/src/file.c index b43f092fa..ea508ce05 100644 --- a/src/file.c +++ b/src/file.c @@ -3,11 +3,10 @@ */ #include "mruby.h" - -#include "mruby/ext/io.h" #include "mruby/class.h" #include "mruby/data.h" #include "mruby/string.h" +#include "mruby/ext/io.h" #if MRUBY_RELEASE_NO < 10000 #include "error.h" @@ -64,101 +63,59 @@ mrb_value mrb_file_s_umask(mrb_state *mrb, mrb_value klass) { - int omask = 0; - #if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) || defined(_WIN64) /* nothing to do on windows */ - #else - mrb_value *argv; - int argc; - mrb_value mask; - - mrb_get_args(mrb, "*", &argv, &argc); + return mrb_fixnum_value(0); - if (argc == 0) { +#else + mrb_int mask, omask; + if (mrb_get_args(mrb, "|i", &mask) == 0) { omask = umask(0); umask(omask); - } else if (argc == 1) { - mask = argv[0]; - if (!mrb_nil_p(mask) && !mrb_fixnum_p(mask)) { - mask = mrb_check_convert_type(mrb, mask, MRB_TT_FIXNUM, "Fixnum", "to_int"); - } - if (!mrb_fixnum_p(mask)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type"); - } - omask = umask(mrb_fixnum(mask)); } else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 0..1)", argc); + omask = umask(mask); } - #endif return mrb_fixnum_value(omask); +#endif } static mrb_value mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) { mrb_value *argv; - int n, i, argc; - const char *path; mrb_value pathv; + int argc, i; + const char *path; mrb_get_args(mrb, "*", &argv, &argc); - for (i = 0, n = 0; i < argc; i++) { - pathv = argv[i]; - if (mrb_type(pathv) != MRB_TT_STRING) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, pathv)); - } + for (i = 0; i < argc; i++) { + pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str"); path = mrb_string_value_cstr(mrb, &pathv);; if (UNLINK(path) < 0) { mrb_sys_fail(mrb, path); - } else { - n++; } } - return mrb_fixnum_value(n); + return mrb_fixnum_value(argc); } static mrb_value -mrb_file_rename_internal(mrb_state *mrb, mrb_value from, mrb_value to) +mrb_file_s_rename(mrb_state *mrb, mrb_value obj) { + mrb_value from, to; const char *src, *dst; + + mrb_get_args(mrb, "SS", &from, &to); src = mrb_string_value_cstr(mrb, &from); dst = mrb_string_value_cstr(mrb, &to); - if (rename(src, dst) < 0) { - if (CHMOD(dst, 0666) == 0 && - UNLINK(dst) == 0 && - rename(src, dst) == 0) + if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) { return mrb_fixnum_value(0); - mrb_sys_fail(mrb, "mrb_file_rename_internal failed."); + } + mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); } - return mrb_fixnum_value(0); } -static mrb_value -mrb_file_s_rename(mrb_state *mrb, mrb_value obj) -{ - mrb_value *argv; - int argc; - - mrb_get_args(mrb, "*", &argv, &argc); - if (argc != 2) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 2)", argc); - return mrb_nil_value(); - } - if (mrb_type(argv[0]) != MRB_TT_STRING) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, argv[0])); - return mrb_nil_value(); - } - if (mrb_type(argv[1]) != MRB_TT_STRING) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %s into String", mrb_obj_classname(mrb, argv[1])); - return mrb_nil_value(); - } - - return mrb_file_rename_internal(mrb, argv[0], argv[1]); -} - - static mrb_value mrb_file_dirname(mrb_state *mrb, mrb_value klass) { @@ -358,8 +315,8 @@ mrb_init_file(mrb_state *mrb) file = mrb_define_class(mrb, "File", io); MRB_SET_INSTANCE_TT(file, MRB_TT_DATA); mrb_define_class_method(mrb, file, "umask", mrb_file_s_umask, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY()); mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY()); mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2)); mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1)); diff --git a/src/io.c b/src/io.c index cbaf523d8..5d024c140 100644 --- a/src/io.c +++ b/src/io.c @@ -69,7 +69,7 @@ mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) flags |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE; break; default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %s", mode); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode)); } while (*m) { @@ -83,7 +83,7 @@ mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) case ':': /* XXX: PASSTHROUGH*/ default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %s", mode); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode)); } } @@ -236,7 +236,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) close(fd); } mrb_proc_exec(pname); - mrb_raisef(mrb, E_IO_ERROR, "command not found: %s", pname); + mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd); _exit(127); } result = mrb_nil_value(); @@ -573,8 +573,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "*", &argv, &argc); if (argc < 1 || argc > 4) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, - "wrong number of arguments (%d for 1..4)", argc); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1..4)", mrb_fixnum_value(argc)); } timeout = mrb_nil_value(); -- cgit v1.2.3 From 9a1b25bdd8b826b3e8cd7b3190c2592aba75d549 Mon Sep 17 00:00:00 2001 From: Julien Ammous Date: Mon, 28 Apr 2014 15:40:04 +0200 Subject: raise an error for flock on solaris --- src/file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/file.c b/src/file.c index ea508ce05..e1db3f960 100644 --- a/src/file.c +++ b/src/file.c @@ -276,7 +276,9 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) mrb_value mrb_file_flock(mrb_state *mrb, mrb_value self) { -#if !defined(sun) +#if defined(sun) + mrb_raise(mrb, E_RUNTIME_ERROR, "flock is not supported on Illumos/Solaris"); +#else mrb_int operation; int fd; -- cgit v1.2.3 From dc61ef1c65e425b1c3c9588c8340c472a6842488 Mon Sep 17 00:00:00 2001 From: windwiny Date: Wed, 7 May 2014 20:33:02 +0800 Subject: compatible 32 bit windows --- src/file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/file.c b/src/file.c index e1db3f960..2c909fb48 100644 --- a/src/file.c +++ b/src/file.c @@ -29,7 +29,9 @@ #define GETCWD _getcwd #define CHMOD(a, b) 0 #define MAXPATHLEN 1024 + #if !defined(PATH_MAX) #define PATH_MAX MAX_PATH + #endif #define realpath(N,R) _fullpath((R),(N),_MAX_PATH) #include #else @@ -127,7 +129,7 @@ mrb_file_dirname(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "S", &s); path = mrb_str_to_cstr(mrb, s); _splitpath((const char*)path, vname, dname, NULL, NULL); - sprintf_s(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname); + snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname); return mrb_str_new_cstr(mrb, buffer); #else char *dname, *path; @@ -154,7 +156,7 @@ mrb_file_basename(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "S", &s); path = mrb_str_to_cstr(mrb, s); _splitpath((const char*)path, NULL, NULL, bname, extname); - sprintf_s(buffer, _MAX_DIR + _MAX_EXT, "%s%s", bname, extname); + snprintf(buffer, _MAX_DIR + _MAX_EXT, "%s%s", bname, extname); return mrb_str_new_cstr(mrb, buffer); #else char *bname, *path; -- cgit v1.2.3 From d894de86f4429aba22055c8319fcf930ac39bdb4 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 10 Jun 2014 10:22:50 +0900 Subject: fd2 is valid if fd2 >= 0. fixes #18. --- src/io.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/io.c b/src/io.c index 5d024c140..a43796b3d 100644 --- a/src/io.c +++ b/src/io.c @@ -646,7 +646,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass) FD_SET(fptr->fd, ep); if (max < fptr->fd) max = fptr->fd; - if (fptr->fd2) { + if (fptr->fd2 >= 0) { FD_SET(fptr->fd2, ep); if (max < fptr->fd2) max = fptr->fd2; @@ -694,7 +694,7 @@ retry: fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(write)[i], &mrb_io_type); if (FD_ISSET(fptr->fd, wp)) { mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]); - } else if (fptr->fd2 && FD_ISSET(fptr->fd2, wp)) { + } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, wp)) { mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]); } } @@ -706,7 +706,7 @@ retry: fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type); if (FD_ISSET(fptr->fd, ep)) { mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]); - } else if (fptr->fd2 && FD_ISSET(fptr->fd2, wp)) { + } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, wp)) { mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]); } } -- cgit v1.2.3 From ddfc4eb5ef170e7eabc7b545366cac389139f044 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 19 Jun 2014 09:57:08 +0900 Subject: IO#read(0) should return "" immediately. fixes iij/mruby-socket#13. --- mrblib/io.rb | 15 ++++++++++----- test/io.rb | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 902d847d2..fceea1171 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -171,11 +171,16 @@ class IO end def read(length = nil) - unless length.nil? or length.class == Fixnum - raise TypeError.new "can't convert #{length.class} into Integer" - end - if length && length < 0 - raise ArgumentError.new "negative length: #{length} given" + unless length.nil? + unless length.is_a? Fixnum + raise TypeError.new "can't convert #{length.class} into Integer" + end + if length < 0 + raise ArgumentError.new "negative length: #{length} given" + end + if length == 0 + return "" # easy case + end end str = '' diff --git a/test/io.rb b/test/io.rb index b5b952425..ebfd2dd54 100644 --- a/test/io.rb +++ b/test/io.rb @@ -93,6 +93,7 @@ assert('IO#read', '15.2.20.5.14') do assert_raise(TypeError) { io.read("str") } len = $mrbtest_io_msg.length + assert_equal '', io.read(0) assert_equal 'mruby', io.read(5) assert_equal $mrbtest_io_msg[5,len], io.read(len) -- cgit v1.2.3 From 59b7c4eaf0e40dc10180f08d3bb958f077c0e305 Mon Sep 17 00:00:00 2001 From: dreamedge Date: Mon, 7 Jul 2014 12:47:53 +0900 Subject: add IO.close_on_exec? --- src/io.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/io.c b/src/io.c index a43796b3d..a550fdf67 100644 --- a/src/io.c +++ b/src/io.c @@ -724,6 +724,47 @@ mrb_io_fileno(mrb_state *mrb, mrb_value io) return mrb_fixnum_value(fptr->fd); } +void +mrb_notimplement(mrb_state *mrb) +{ + mrb_raise(mrb, E_SCRIPT_ERROR, "unimplemented on this machine"); + + return -1; +} + +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) +mrb_value +mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) +{ + struct mrb_io *fptr; + mrb_value write_io; + int fd, ret; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + if(fptr->fd2 >= 0){ + if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if (!(ret & FD_CLOEXEC)) return mrb_bool_value(0); + } + + if(fptr->fd < 0){ + mrb_raise(mrb, E_IO_ERROR, "closed stream"); + } else { + if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if (!(ret & FD_CLOEXEC)) return mrb_bool_value(0); + } + + return mrb_bool_value(1); +} +#else +#define mrb_io_close_on_exec_p mrb_f_notimplement +mrb_f_notimplement(mrb_state *mrb, mrb_value io) +{ + mrb_notimplement(); + + return -1; +} +#endif + void mrb_init_io(mrb_state *mrb) { @@ -749,5 +790,8 @@ mrb_init_io(mrb_state *mrb) mrb_define_method(mrb, io, "pid", mrb_io_pid, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE()); + mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p, MRB_ARGS_NONE()); +/* mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1));*/ + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); } -- cgit v1.2.3 From 7e689e8680fec8f644344e110af11fa658c9f189 Mon Sep 17 00:00:00 2001 From: dreamedge Date: Tue, 8 Jul 2014 15:56:56 +0900 Subject: Add IO#close_on_exec= and a test on test/io.rb --- src/io.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++---- test/io.rb | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/src/io.c b/src/io.c index a550fdf67..5e4ec6e7d 100644 --- a/src/io.c +++ b/src/io.c @@ -729,7 +729,7 @@ mrb_notimplement(mrb_state *mrb) { mrb_raise(mrb, E_SCRIPT_ERROR, "unimplemented on this machine"); - return -1; + return; } #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) @@ -737,8 +737,7 @@ mrb_value mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; - mrb_value write_io; - int fd, ret; + int ret; fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); if(fptr->fd2 >= 0){ @@ -765,6 +764,54 @@ mrb_f_notimplement(mrb_state *mrb, mrb_value io) } #endif +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) +mrb_value +mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) +{ + mrb_bool bool; + int flag; + struct mrb_io *fptr; + int ret; + + mrb_get_args(mrb, "b", &bool); + flag = bool ? FD_CLOEXEC : 0; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + + if(fptr->fd2 >= 0){ + if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if ((ret & FD_CLOEXEC) != flag) { + ret = (ret & ~FD_CLOEXEC) | flag; + ret = fcntl(fptr->fd2, F_SETFD, ret); + + if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed"); + } + } + + if(fptr->fd < 0){ + mrb_raise(mrb, E_IO_ERROR, "closed stream"); + } else { + if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if ((ret & FD_CLOEXEC) != flag) { + ret = (ret & ~FD_CLOEXEC) | flag; + ret = fcntl(fptr->fd, F_SETFD, ret); + if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed"); + } + } + + return mrb_nil_value(); +} +#else +#define mrb_io_close_on_exec mrb_f_notimplement +mrb_f_notimplement(mrb_state *mrb, mrb_value io) +{ + mrb_notimplement(); + + return -1; +} +#endif + + void mrb_init_io(mrb_state *mrb) { @@ -791,7 +838,7 @@ mrb_init_io(mrb_state *mrb) mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p, MRB_ARGS_NONE()); -/* mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1));*/ + mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1)); mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); } diff --git a/test/io.rb b/test/io.rb index ebfd2dd54..b4110044b 100644 --- a/test/io.rb +++ b/test/io.rb @@ -1,6 +1,8 @@ ## # IO Test +print "test start\n" + assert('IO TEST SETUP') do MRubyIOTestUtil.io_test_setup end @@ -342,6 +344,50 @@ assert('IO#fileno') do io.closed? end +assert('IO#close_on_exec') do + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + begin + # IO.sysopen opens a file descripter without O_CLOEXEC flag. + assert_equal(false, io.close_on_exec?) + rescue ScriptError + skip "IO\#close_on_exec is not implemented." + end + + io.close_on_exec = true + assert_equal(true, io.close_on_exec?) + io.close_on_exec = false + assert_equal(false, io.close_on_exec?) + io.close_on_exec = true + assert_equal(true, io.close_on_exec?) + + io.close + io.closed? + + # # Use below when IO.pipe is implemented. + # begin + # r, w = IO.pipe + # assert_equal(false, r.close_on_exec?) + # r.close_on_exec = true + # assert_equal(true, r.close_on_exec?) + # r.close_on_exec = false + # assert_equal(false, r.close_on_exec?) + # r.close_on_exec = true + # assert_equal(true, r.close_on_exec?) + + # assert_equal(false, w.close_on_exec?) + # w.close_on_exec = true + # assert_equal(true, w.close_on_exec?) + # w.close_on_exec = false + # assert_equal(false, w.close_on_exec?) + # w.close_on_exec = true + # assert_equal(true, w.close_on_exec?) + # ensure + # r.close unless r.closed? + # w.close unless w.closed? + # end +end + assert('`cmd`') do assert_equal `echo foo`, "foo\n" end -- cgit v1.2.3 From 78f5f98710ba19745defd2a36e7a50649c88006e Mon Sep 17 00:00:00 2001 From: dreamedge Date: Wed, 9 Jul 2014 05:29:20 +0900 Subject: delete debug messages --- test/io.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/io.rb b/test/io.rb index b4110044b..cbe3cd2b0 100644 --- a/test/io.rb +++ b/test/io.rb @@ -1,8 +1,6 @@ ## # IO Test -print "test start\n" - assert('IO TEST SETUP') do MRubyIOTestUtil.io_test_setup end -- cgit v1.2.3 From fa39825b1bac290f42dbd9f0605d87e40f67acfb Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 9 Jul 2014 10:01:33 +0900 Subject: refactor. --- src/io.c | 89 +++++++++++++++++++++++++--------------------------------------- 1 file changed, 34 insertions(+), 55 deletions(-) diff --git a/src/io.c b/src/io.c index 5e4ec6e7d..f6ce44840 100644 --- a/src/io.c +++ b/src/io.c @@ -724,61 +724,50 @@ mrb_io_fileno(mrb_state *mrb, mrb_value io) return mrb_fixnum_value(fptr->fd); } -void -mrb_notimplement(mrb_state *mrb) -{ - mrb_raise(mrb, E_SCRIPT_ERROR, "unimplemented on this machine"); - - return; -} - -#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) mrb_value mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) { +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) struct mrb_io *fptr; int ret; fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); - if(fptr->fd2 >= 0){ - if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); - if (!(ret & FD_CLOEXEC)) return mrb_bool_value(0); + if (fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream"); } - if(fptr->fd < 0){ - mrb_raise(mrb, E_IO_ERROR, "closed stream"); - } else { - if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); - if (!(ret & FD_CLOEXEC)) return mrb_bool_value(0); + if (fptr->fd2 >= 0) { + if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if (!(ret & FD_CLOEXEC)) return mrb_false_value(); } - return mrb_bool_value(1); -} -#else -#define mrb_io_close_on_exec_p mrb_f_notimplement -mrb_f_notimplement(mrb_state *mrb, mrb_value io) -{ - mrb_notimplement(); + if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if (!(ret & FD_CLOEXEC)) return mrb_false_value(); + return mrb_true_value(); - return -1; -} +#else + mrb_raise(mrb, E_NOTIMPL_ERROR, "IO#close_on_exec? is not supported on the platform"); + return mrb_false_value(); #endif +} -#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) mrb_value mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) { - mrb_bool bool; - int flag; +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) struct mrb_io *fptr; - int ret; - - mrb_get_args(mrb, "b", &bool); - flag = bool ? FD_CLOEXEC : 0; + int flag, ret; + mrb_bool b; fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + if (fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream"); + } - if(fptr->fd2 >= 0){ + mrb_get_args(mrb, "b", &b); + flag = b ? FD_CLOEXEC : 0; + + if (fptr->fd2 >= 0) { if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); if ((ret & FD_CLOEXEC) != flag) { ret = (ret & ~FD_CLOEXEC) | flag; @@ -788,29 +777,19 @@ mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) } } - if(fptr->fd < 0){ - mrb_raise(mrb, E_IO_ERROR, "closed stream"); - } else { - if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); - if ((ret & FD_CLOEXEC) != flag) { - ret = (ret & ~FD_CLOEXEC) | flag; - ret = fcntl(fptr->fd, F_SETFD, ret); - if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed"); - } + if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); + if ((ret & FD_CLOEXEC) != flag) { + ret = (ret & ~FD_CLOEXEC) | flag; + ret = fcntl(fptr->fd, F_SETFD, ret); + if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed"); } - return mrb_nil_value(); -} + return mrb_bool_value(b); #else -#define mrb_io_close_on_exec mrb_f_notimplement -mrb_f_notimplement(mrb_state *mrb, mrb_value io) -{ - mrb_notimplement(); - - return -1; -} + mrb_raise(mrb, E_NOTIMPL_ERROR, "IO#close_on_exec= is not supported on the platform"); + return mrb_nil_value(); #endif - +} void mrb_init_io(mrb_state *mrb) @@ -833,12 +812,12 @@ mrb_init_io(mrb_state *mrb) mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1)); mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, MRB_ARGS_REQ(1)); mrb_define_method(mrb, io, "close", mrb_io_close, MRB_ARGS_NONE()); /* 15.2.20.5.1 */ + mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "closed?", mrb_io_closed, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ mrb_define_method(mrb, io, "pid", mrb_io_pid, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE()); - mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p, MRB_ARGS_NONE()); - mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1)); mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n")); } -- cgit v1.2.3 From 689541d0fb73319082d617af87003b9d04510eae Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Sat, 19 Jul 2014 21:37:13 +0900 Subject: Fix type of argument passed to mrb_get_args. --- src/file.c | 2 +- src/io.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/file.c b/src/file.c index 2c909fb48..f8d6bc179 100644 --- a/src/file.c +++ b/src/file.c @@ -86,7 +86,7 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) { mrb_value *argv; mrb_value pathv; - int argc, i; + mrb_int argc, i; const char *path; mrb_get_args(mrb, "*", &argv, &argc); diff --git a/src/io.c b/src/io.c index f6ce44840..39e5bc94b 100644 --- a/src/io.c +++ b/src/io.c @@ -398,7 +398,8 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; mrb_value buf = mrb_nil_value(); - int maxlen, ret; + mrb_int maxlen; + int ret; mrb_get_args(mrb, "i|S", &maxlen, &buf); if (maxlen < 0) { @@ -439,7 +440,8 @@ mrb_value mrb_io_sysseek(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; - int pos, offset, whence = -1; + int pos; + mrb_int offset, whence = -1; mrb_get_args(mrb, "i|i", &offset, &whence); if (whence < 0) { @@ -558,7 +560,7 @@ static mrb_value mrb_io_s_select(mrb_state *mrb, mrb_value klass) { mrb_value *argv; - int argc; + mrb_int argc; mrb_value read, read_io, write, except, timeout, list; struct timeval *tp, timerec; fd_set pset, rset, wset, eset; -- cgit v1.2.3 From 1768ee02e5b74c2a54fa312550700ed469f7b7db Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 22 Jul 2014 23:55:25 +0900 Subject: remove extra ';'. --- src/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/file.c b/src/file.c index f8d6bc179..2402a3060 100644 --- a/src/file.c +++ b/src/file.c @@ -92,7 +92,7 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) mrb_get_args(mrb, "*", &argv, &argc); for (i = 0; i < argc; i++) { pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str"); - path = mrb_string_value_cstr(mrb, &pathv);; + path = mrb_string_value_cstr(mrb, &pathv); if (UNLINK(path) < 0) { mrb_sys_fail(mrb, path); } -- cgit v1.2.3 From e60951a3052d4e38dea21566feb02cf901b6646a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 29 Jul 2014 10:55:02 +0900 Subject: add IO#sync and IO#sync= --- README.md | 4 ++-- include/mruby/ext/io.h | 4 ++-- src/io.c | 33 +++++++++++++++++++++++++++++++++ test/io.rb | 24 ++++++++++++++++++++++-- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ee7d640eb..e8407a662 100644 --- a/README.md +++ b/README.md @@ -79,8 +79,8 @@ IO, File module for mruby | IO#seek | o | | | IO#set_encoding | | | | IO#stat | | | -| IO#sync | | | -| IO#sync= | | | +| IO#sync | o | | +| IO#sync= | o | | | IO#sysread | o | | | IO#sysseek | o | | | IO#syswrite | o | | diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index 7d61ba267..3107f1053 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -13,14 +13,14 @@ struct mrb_io { int fd; /* file descriptor, or -1 */ int fd2; /* file descriptor to write if it's different from fd, or -1 */ int pid; /* child's pid (for pipes) */ - unsigned int writable:1; + unsigned int writable:1, + sync:1; }; #define FMODE_READABLE 0x00000001 #define FMODE_WRITABLE 0x00000002 #define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE) #define FMODE_BINMODE 0x00000004 -#define FMODE_SYNC 0x00000008 #define FMODE_APPEND 0x00000040 #define FMODE_CREATE 0x00000080 #define FMODE_TRUNC 0x00000800 diff --git a/src/io.c b/src/io.c index 39e5bc94b..bcf5c8f22 100644 --- a/src/io.c +++ b/src/io.c @@ -167,6 +167,7 @@ mrb_io_alloc(mrb_state *mrb) fptr->fd2 = -1; fptr->pid = 0; fptr->writable = 0; + fptr->sync = 0; return fptr; } @@ -264,6 +265,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) fptr->fd2 = write_fd; fptr->pid = pid; fptr->writable = ((flags & FMODE_WRITABLE) != 0); + fptr->sync = 0; DATA_TYPE(io) = &mrb_io_type; DATA_PTR(io) = fptr; @@ -323,6 +325,7 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) fptr->fd = fd; fptr->writable = ((flags & FMODE_WRITABLE) != 0); + fptr->sync = 0; return io; } @@ -793,6 +796,34 @@ mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) #endif } +mrb_value +mrb_io_set_sync(mrb_state *mrb, mrb_value self) +{ + struct mrb_io *fptr; + mrb_bool b; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); + if (fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream."); + } + + mrb_get_args(mrb, "b", &b); + fptr->sync = b; + return mrb_bool_value(b); +} + +mrb_value +mrb_io_sync(mrb_state *mrb, mrb_value self) +{ + struct mrb_io *fptr; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); + if (fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream."); + } + return mrb_bool_value(fptr->sync); +} + void mrb_init_io(mrb_state *mrb) { @@ -810,6 +841,8 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ + mrb_define_method(mrb, io, "sync", mrb_io_sync, MRB_ARGS_NONE()); + mrb_define_method(mrb, io, "sync=", mrb_io_set_sync, MRB_ARGS_REQ(1)); mrb_define_method(mrb, io, "sysread", mrb_io_sysread, MRB_ARGS_ANY()); mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1)); mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, MRB_ARGS_REQ(1)); diff --git a/test/io.rb b/test/io.rb index cbe3cd2b0..006c7cc8d 100644 --- a/test/io.rb +++ b/test/io.rb @@ -120,8 +120,28 @@ end #assert('IO#readline', '15.2.20.5.16') do #assert('IO#readlines', '15.2.20.5.17') do -#assert('IO#sync', '15.2.20.5.18') do -#assert('IO#sync=', '15.2.20.5.19') do + +assert('IO#sync', '15.2.20.5.18') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + s = io.sync + assert_true(s == true || s == false) + io.close + assert_raise(IOError) do + io.sync + end +end + +assert('IO#sync=', '15.2.20.5.19') do + io = IO.new(IO.sysopen($mrbtest_io_rfname)) + io.sync = true + assert_true io.sync + io.sync = false + assert_false io.sync + io.close + assert_raise(IOError) do + io.sync = true + end +end assert('IO#write', '15.2.20.5.20') do io = IO.open(IO.sysopen($mrbtest_io_wfname)) -- cgit v1.2.3 From 9a2cbc41226c801d139c430215f3f73321dc76b7 Mon Sep 17 00:00:00 2001 From: jbreeden Date: Sun, 3 Aug 2014 16:45:46 -0400 Subject: Correcting E_NOTIMP_ERROR reference --- src/io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/io.c b/src/io.c index bcf5c8f22..e6d289c65 100644 --- a/src/io.c +++ b/src/io.c @@ -751,7 +751,7 @@ mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) return mrb_true_value(); #else - mrb_raise(mrb, E_NOTIMPL_ERROR, "IO#close_on_exec? is not supported on the platform"); + mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec? is not supported on the platform"); return mrb_false_value(); #endif } @@ -791,7 +791,7 @@ mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) return mrb_bool_value(b); #else - mrb_raise(mrb, E_NOTIMPL_ERROR, "IO#close_on_exec= is not supported on the platform"); + mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec= is not supported on the platform"); return mrb_nil_value(); #endif } -- cgit v1.2.3 From 0761b172459199417cfe18752d1ee8b1b19ba989 Mon Sep 17 00:00:00 2001 From: Akito Mochizuki Date: Tue, 5 Aug 2014 11:51:05 +0900 Subject: update implemented methods table --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e8407a662..d7fa6945b 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ IO, File module for mruby | IO.popen | o | | | IO.read | o | | | IO.readlines | | | -| IO.select | | | +| IO.select | o | | | IO.sysopen | o | | | IO.try_convert | | | | IO.write | | | @@ -34,8 +34,8 @@ IO, File module for mruby | IO#chars | | obsolete | | IO#clone, IO#dup | | | | IO#close | o | | -| IO#close_on_exec= | | | -| IO#close_on_exec? | | | +| IO#close_on_exec= | o | | +| IO#close_on_exec? | o | | | IO#close_read | | | | IO#close_write | | | | IO#closed? | o | | @@ -48,8 +48,8 @@ IO, File module for mruby | IO#external_encoding | | | | IO#fcntl | | | | IO#fdatasync | | | -| IO#fileno, IO#to_i | | | -| IO#flush | | | +| IO#fileno, IO#to_i | o | | +| IO#flush | o | | | IO#fsync | | | | IO#getbyte | | | | IO#getc | o | | @@ -109,7 +109,7 @@ IO, File module for mruby | File.executable? | | FileTest | | File.executable_real? | | FileTest | | File.exist?, exists? | o | FileTest | -| File.expand_path | | | +| File.expand_path | o | | | File.extname | o | | | File.file? | o | FileTest | | File.fnmatch, File.fnmatch? | | | -- cgit v1.2.3 From b50093ad28b7f068da38ed0c702aa8c615584576 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 13 Nov 2014 01:50:46 +0900 Subject: garbage collect when open(2) fails with ENFILE or EMFILE --- src/io.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index e6d289c65..d7e1b0fba 100644 --- a/src/io.c +++ b/src/io.c @@ -374,7 +374,7 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) mrb_value mode = mrb_nil_value(); mrb_int fd, flags, perm = -1; const char *pat; - int modenum; + int modenum, retry = FALSE; mrb_get_args(mrb, "S|Si", &path, &mode, &perm); if (mrb_nil_p(mode)) { @@ -388,8 +388,18 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); modenum = mrb_io_flags_to_modenum(mrb, flags); + reopen: fd = open(pat, modenum, perm); if (fd == -1) { + if (!retry) { + switch (errno) { + case ENFILE: + case EMFILE: + mrb_garbage_collect(mrb); + retry = TRUE; + goto reopen; + } + } mrb_sys_fail(mrb, pat); } -- cgit v1.2.3 From a44ada616ee32b993f40e50b7e5d45f54ce846d2 Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 16 Nov 2014 14:55:45 +0900 Subject: Implement FileTest.size - File.size delegate to FileTest.size - File.size more faster by reading i-node value --- mrblib/file.rb | 4 ++++ src/file.c | 33 ++------------------------------- src/file_test.c | 25 ++++++++++++++++++++++++- test/file.rb | 6 ------ test/file_test.rb | 5 +++++ 5 files changed, 35 insertions(+), 38 deletions(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index 5a2716a66..18383f303 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -151,6 +151,10 @@ class File < IO FileTest.pipe?(file) end + def self.size(file) + FileTest.size(file) + end + def self.size?(file) FileTest.size?(file) end diff --git a/src/file.c b/src/file.c index 2402a3060..f8a0fb2c0 100644 --- a/src/file.c +++ b/src/file.c @@ -192,34 +192,6 @@ mrb_file_realpath(mrb_state *mrb, mrb_value klass) return result; } -static mrb_value -mrb_file_size(mrb_state *mrb, mrb_value klass) -{ - char *cp; - FILE *fp; - mrb_int filesize; - mrb_value s; - int saved_errno; - - mrb_get_args(mrb, "S", &s); - cp = mrb_str_to_cstr(mrb, s); - fp = fopen(cp, "rb"); - if (fp == NULL) { - mrb_sys_fail(mrb, "fopen"); - return mrb_nil_value(); - } - if (fseek(fp, 0, SEEK_END) != 0) { - saved_errno = errno; - fclose(fp); - errno = saved_errno; - mrb_sys_fail(mrb, "fseek"); - return mrb_nil_value(); - } - filesize = (mrb_int) ftell(fp); - fclose(fp); - return mrb_fixnum_value(filesize); -} - mrb_value mrb_file__getwd(mrb_state *mrb, mrb_value klass) { @@ -269,7 +241,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } return mrb_str_new_cstr(mrb, home); #else - + return mrb_nil_value(); #endif } @@ -326,14 +298,13 @@ mrb_init_file(mrb_state *mrb) mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, file, "basename", mrb_file_basename, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, file, "realpath", mrb_file_realpath, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1)); - mrb_define_class_method(mrb, file, "size", mrb_file_size, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, MRB_ARGS_NONE()); mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1)); #ifndef _WIN32 mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1)); #endif - + cnst = mrb_define_module_under(mrb, file, "Constants"); mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH)); mrb_define_const(mrb, cnst, "LOCK_EX", mrb_fixnum_value(LOCK_EX)); diff --git a/src/file_test.c b/src/file_test.c index d3dfb15ba..6c380c4a5 100644 --- a/src/file_test.c +++ b/src/file_test.c @@ -298,6 +298,29 @@ mrb_filetest_s_zero_p(mrb_state *mrb, mrb_value klass) return mrb_false_value(); } +/* + * call-seq: + * File.size(file_name) -> integer + * + * Returns the size of file_name. + * + * _file_name_ can be an IO object. + */ + +mrb_value +mrb_filetest_s_size(mrb_state *mrb, mrb_value klass) +{ + struct stat st; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + if (mrb_stat(mrb, obj, &st) < 0) + mrb_sys_fail(mrb, "mrb_stat"); + + return mrb_fixnum_value(st.st_size); +} + /* * call-seq: * File.size?(file_name) -> Integer or nil @@ -322,7 +345,6 @@ mrb_filetest_s_size_p(mrb_state *mrb, mrb_value klass) return mrb_fixnum_value(st.st_size); } - void mrb_init_file_test(mrb_state *mrb) { @@ -335,6 +357,7 @@ mrb_init_file_test(mrb_state *mrb) mrb_define_class_method(mrb, f, "exists?", mrb_filetest_s_exist_p, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, f, "file?", mrb_filetest_s_file_p, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, f, "pipe?", mrb_filetest_s_pipe_p, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, f, "size", mrb_filetest_s_size, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, f, "size?", mrb_filetest_s_size_p, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, f, "socket?", mrb_filetest_s_socket_p, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, f, "symlink?", mrb_filetest_s_symlink_p, MRB_ARGS_REQ(1)); diff --git a/test/file.rb b/test/file.rb index c8df85e89..d6f39ceb1 100644 --- a/test/file.rb +++ b/test/file.rb @@ -64,12 +64,6 @@ assert('IO#flock') do true end - -assert('File.size') do - File.size($mrbtest_io_rfname) == $mrbtest_io_msg.size and - File.size($mrbtest_io_wfname) == 0 -end - assert('File.join') do File.join() == "" and File.join("a") == "a" and diff --git a/test/file_test.rb b/test/file_test.rb index 1fe6a8fd8..11742f2db 100644 --- a/test/file_test.rb +++ b/test/file_test.rb @@ -33,6 +33,11 @@ assert("FileTest.pipe?") do assert_equal false, FileTest.pipe?("/tmp") end +assert('FileTest.size') do + assert_equal FileTest.size($mrbtest_io_rfname), $mrbtest_io_msg.size + assert_equal FileTest.size($mrbtest_io_wfname), 0 +end + assert("FileTest.size?") do assert_equal $mrbtest_io_msg.size, FileTest.size?($mrbtest_io_rfname) assert_equal nil, FileTest.size?($mrbtest_io_wfname) -- cgit v1.2.3 From 24007b80b48e92ec4b9b2ac226b8b1e52b1a3c8f Mon Sep 17 00:00:00 2001 From: sdottaka Date: Sat, 22 Nov 2014 17:48:59 +0900 Subject: Fix broken build for Visual C++ --- src/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/file.c b/src/file.c index f8a0fb2c0..c2419c2cc 100644 --- a/src/file.c +++ b/src/file.c @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -30,11 +29,12 @@ #define CHMOD(a, b) 0 #define MAXPATHLEN 1024 #if !defined(PATH_MAX) - #define PATH_MAX MAX_PATH + #define PATH_MAX _MAX_PATH #endif #define realpath(N,R) _fullpath((R),(N),_MAX_PATH) #include #else + #include #define UNLINK unlink #define GETCWD getcwd #define CHMOD(a, b) chmod(a,b) -- cgit v1.2.3 From d1fee5892adb23565fddd9f8e762cc4ca8fd8cb3 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 25 Nov 2014 16:26:34 +0900 Subject: IO.sysopen does retry. closes #26. --- mrblib/file.rb | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index 18383f303..aa0981930 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -13,14 +13,7 @@ class File < IO super(fd_or_path, mode) else @path = fd_or_path - begin - fd = IO.sysopen(@path, mode, perm) - rescue RuntimeError => e - raise FileError, "Could not open file (#{e})" - rescue Errno::EMFILE, Errno::ENFILE - GC.start - fd = IO.sysopen(@path, mode, perm) - end + fd = IO.sysopen(@path, mode, perm) super(fd, mode) end end -- cgit v1.2.3 From 9439b981d816a25883bd9d8f05af62664f21e0bc Mon Sep 17 00:00:00 2001 From: ksss Date: Thu, 4 Dec 2014 09:05:24 +0900 Subject: Opened fd should be set FD_CLOEXEC by default --- src/io.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++--------------- test/io.rb | 16 ++++++------- 2 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/io.c b/src/io.c index d7e1b0fba..560fba3de 100644 --- a/src/io.c +++ b/src/io.c @@ -125,6 +125,30 @@ mrb_io_flags_to_modenum(mrb_state *mrb, int flags) return modenum; } +void +mrb_fd_cloexec(mrb_state *mrb, int fd) +{ + int flags, flags2; + +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) + flags = fcntl(fd, F_GETFD); + if (flags == -1) { + mrb_sys_fail(mrb, "fcntl"); + } + if (fd <= 2) { + flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */ + } + else { + flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */ + } + if (flags != flags2) { + if (fcntl(fd, F_SETFD, flags2) == -1) { + mrb_sys_fail(mrb, "fcntl"); + } + } +#endif +} + #ifndef _WIN32 static int mrb_proc_exec(const char *pname) @@ -367,6 +391,38 @@ mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass) return mrb_fixnum_value(0); } +int +mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode) +{ + int fd, retry = FALSE; + +#ifdef O_CLOEXEC + /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */ + flags |= O_CLOEXEC; +#elif defined O_NOINHERIT + flags |= O_NOINHERIT; +#endif +reopen: + fd = open(pathname, flags, mode); + if (fd == -1) { + if (!retry) { + switch (errno) { + case ENFILE: + case EMFILE: + mrb_garbage_collect(mrb); + retry = TRUE; + goto reopen; + } + } + mrb_sys_fail(mrb, "open"); + } + + if (fd <= 2) { + mrb_fd_cloexec(mrb, fd); + } + return fd; +} + mrb_value mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) { @@ -374,7 +430,7 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) mrb_value mode = mrb_nil_value(); mrb_int fd, flags, perm = -1; const char *pat; - int modenum, retry = FALSE; + int modenum; mrb_get_args(mrb, "S|Si", &path, &mode, &perm); if (mrb_nil_p(mode)) { @@ -387,22 +443,7 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) pat = mrb_string_value_cstr(mrb, &path); flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); modenum = mrb_io_flags_to_modenum(mrb, flags); - - reopen: - fd = open(pat, modenum, perm); - if (fd == -1) { - if (!retry) { - switch (errno) { - case ENFILE: - case EMFILE: - mrb_garbage_collect(mrb); - retry = TRUE; - goto reopen; - } - } - mrb_sys_fail(mrb, pat); - } - + fd = mrb_cloexec_open(mrb, pat, modenum, perm); return mrb_fixnum_value(fd); } @@ -745,7 +786,7 @@ mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) struct mrb_io *fptr; int ret; - + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); if (fptr->fd < 0) { mrb_raise(mrb, E_IO_ERROR, "closed stream"); @@ -787,7 +828,7 @@ mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) if ((ret & FD_CLOEXEC) != flag) { ret = (ret & ~FD_CLOEXEC) | flag; ret = fcntl(fptr->fd2, F_SETFD, ret); - + if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed"); } } diff --git a/test/io.rb b/test/io.rb index 006c7cc8d..9c7ce741f 100644 --- a/test/io.rb +++ b/test/io.rb @@ -362,28 +362,28 @@ assert('IO#fileno') do io.closed? end -assert('IO#close_on_exec') do +assert('IO#close_on_exec') do fd = IO.sysopen $mrbtest_io_wfname, "w" io = IO.new fd, "w" - begin - # IO.sysopen opens a file descripter without O_CLOEXEC flag. - assert_equal(false, io.close_on_exec?) + begin + # IO.sysopen opens a file descripter with O_CLOEXEC flag. + assert_true io.close_on_exec? rescue ScriptError skip "IO\#close_on_exec is not implemented." end - io.close_on_exec = true - assert_equal(true, io.close_on_exec?) io.close_on_exec = false assert_equal(false, io.close_on_exec?) io.close_on_exec = true assert_equal(true, io.close_on_exec?) - + io.close_on_exec = false + assert_equal(false, io.close_on_exec?) + io.close io.closed? # # Use below when IO.pipe is implemented. - # begin + # begin # r, w = IO.pipe # assert_equal(false, r.close_on_exec?) # r.close_on_exec = true -- cgit v1.2.3 From e61c46972482ca2b4e9b338f9ccfa4ee13efa62d Mon Sep 17 00:00:00 2001 From: ksss Date: Thu, 4 Dec 2014 10:21:29 +0900 Subject: IO.popen fd set close_on_exec flag by default --- src/io.c | 21 +++++++++++++++------ test/io.rb | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/io.c b/src/io.c index 560fba3de..3f299775e 100644 --- a/src/io.c +++ b/src/io.c @@ -223,13 +223,22 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) doexec = (strcmp("-", pname) != 0); - if ((flags & FMODE_READABLE) && pipe(pr) == -1) { - mrb_sys_fail(mrb, "pipe"); + if (flags & FMODE_READABLE) { + if (pipe(pr) == -1) { + mrb_sys_fail(mrb, "pipe"); + } + mrb_fd_cloexec(mrb, pr[0]); + mrb_fd_cloexec(mrb, pr[1]); } - if ((flags & FMODE_WRITABLE) && pipe(pw) == -1) { - if (pr[0] != -1) close(pr[0]); - if (pr[1] != -1) close(pr[1]); - mrb_sys_fail(mrb, "pipe"); + + if (flags & FMODE_WRITABLE) { + if (pipe(pw) == -1) { + if (pr[0] != -1) close(pr[0]); + if (pr[1] != -1) close(pr[1]); + mrb_sys_fail(mrb, "pipe"); + } + mrb_fd_cloexec(mrb, pw[0]); + mrb_fd_cloexec(mrb, pw[1]); } if (!doexec) { diff --git a/test/io.rb b/test/io.rb index 9c7ce741f..b828fef49 100644 --- a/test/io.rb +++ b/test/io.rb @@ -321,6 +321,7 @@ end assert('IO.popen') do io = IO.popen("ls") + assert_true io.close_on_exec? assert_equal Fixnum, io.pid.class ls = io.read assert_equal ls.class, String -- cgit v1.2.3 From be9e203563b761f271abc58e1854f027ad808641 Mon Sep 17 00:00:00 2001 From: TOMITA Masahiro Date: Mon, 15 Dec 2014 20:24:01 +0900 Subject: FIX: IO#sysread occurs SEGV --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index d7e1b0fba..e80483145 100644 --- a/src/io.c +++ b/src/io.c @@ -420,7 +420,7 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) } if (mrb_nil_p(buf)) { - buf = mrb_str_new(mrb, "", maxlen); + buf = mrb_str_new(mrb, NULL, maxlen); } if (RSTRING_LEN(buf) != maxlen) { buf = mrb_str_resize(mrb, buf, maxlen); -- cgit v1.2.3 From 9b13a59a55f43486112d98ec5df905b1fd2fdf94 Mon Sep 17 00:00:00 2001 From: TOMITA Masahiro Date: Wed, 17 Dec 2014 01:05:59 +0900 Subject: FIX: IO#read create a large number of objects. --- mrblib/io.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index fceea1171..51a395119 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -194,12 +194,12 @@ class IO if length && (str.size + @buf.size) >= length len = length - str.size - str += @buf[0, len] + str << @buf[0, len] @pos += len @buf = @buf[len, @buf.size - len] break else - str += @buf + str << @buf @pos += @buf.size @buf = '' end @@ -238,18 +238,18 @@ class IO if limit && (str.size + @buf.size) >= limit len = limit - str.size - str += @buf[0, len] + str << @buf[0, len] @pos += len @buf = @buf[len, @buf.size - len] break elsif idx = @buf.index(rs) len = idx + rs.size - str += @buf[0, len] + str << @buf[0, len] @pos += len @buf = @buf[len, @buf.size - len] break else - str += @buf + str << @buf @pos += @buf.size @buf = '' end -- cgit v1.2.3 From e82c1d3f3829cd9057017a0848b9c101c4aab46a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 17 Dec 2014 13:37:15 +0900 Subject: Revert "FIX: IO#read create a large number of objects." --- mrblib/io.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 51a395119..fceea1171 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -194,12 +194,12 @@ class IO if length && (str.size + @buf.size) >= length len = length - str.size - str << @buf[0, len] + str += @buf[0, len] @pos += len @buf = @buf[len, @buf.size - len] break else - str << @buf + str += @buf @pos += @buf.size @buf = '' end @@ -238,18 +238,18 @@ class IO if limit && (str.size + @buf.size) >= limit len = limit - str.size - str << @buf[0, len] + str += @buf[0, len] @pos += len @buf = @buf[len, @buf.size - len] break elsif idx = @buf.index(rs) len = idx + rs.size - str << @buf[0, len] + str += @buf[0, len] @pos += len @buf = @buf[len, @buf.size - len] break else - str << @buf + str += @buf @pos += @buf.size @buf = '' end -- cgit v1.2.3 From 42752bffce566cdfe945db34101ff42d406918c9 Mon Sep 17 00:00:00 2001 From: TOMITA Masahiro Date: Thu, 18 Dec 2014 00:29:15 +0900 Subject: FIX: IO#read create a large number of objects. --- mrblib/io.rb | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index fceea1171..be715ba7a 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -183,29 +183,30 @@ class IO end end - str = '' + array = [] + start_pos = @pos while 1 begin _read_buf rescue EOFError => e - str = nil if str.empty? and (not length.nil?) and length != 0 + array = nil if array.empty? and (not length.nil?) and length != 0 break end - if length && (str.size + @buf.size) >= length - len = length - str.size - str += @buf[0, len] + if length && (@pos - start_pos + @buf.size) >= length + len = length - (@pos - start_pos) + array.push @buf[0, len] @pos += len @buf = @buf[len, @buf.size - len] break else - str += @buf + array.push @buf @pos += @buf.size @buf = '' end end - str + array && array.join end def readline(arg = $/, limit = nil) @@ -227,37 +228,38 @@ class IO rs = $/ + $/ end - str = "" + array = [] + start_pos = @pos while 1 begin _read_buf rescue EOFError => e - str = nil if str.empty? + array = nil if array.empty? break end - if limit && (str.size + @buf.size) >= limit - len = limit - str.size - str += @buf[0, len] + if limit && (@pos - start_pos + @buf.size) >= limit + len = limit - (@pos - start_pos) + array.push @buf[0, len] @pos += len @buf = @buf[len, @buf.size - len] break elsif idx = @buf.index(rs) len = idx + rs.size - str += @buf[0, len] + array.push @buf[0, len] @pos += len @buf = @buf[len, @buf.size - len] break else - str += @buf + array.push @buf @pos += @buf.size @buf = '' end end - raise EOFError.new "end of file reached" if str.nil? + raise EOFError.new "end of file reached" if array.nil? - str + array.join end def gets(*args) -- cgit v1.2.3 From c455544ee28e440f371c4f758f2b31ee69ec0877 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 26 Dec 2014 11:08:18 +0900 Subject: better error message. --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index e80483145..5a6079e99 100644 --- a/src/io.c +++ b/src/io.c @@ -437,7 +437,7 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) } break; case -1: /* Error */ - mrb_raise(mrb, E_IO_ERROR, "sysread failed"); + mrb_sys_fail(mrb, "sysread failed"); break; default: if (RSTRING_LEN(buf) != ret) { -- cgit v1.2.3 From 3a97a453c486cd1ce9456970b686ab24f8126980 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 26 Dec 2014 11:09:07 +0900 Subject: rewrite IO.for_fd. IO.for_fd should call IO#initialize to initialize the created object properly. It cannot be implemented in Ruby. --- mrblib/io.rb | 4 ---- src/io.c | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index be715ba7a..c838b96e5 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -11,10 +11,6 @@ class IO BUF_SIZE = 4096 - def self.for_fd *args - self.new(*args) - end - def self.open(*args, &block) io = self.new(*args) diff --git a/src/io.c b/src/io.c index 5a6079e99..4f7fd25f0 100644 --- a/src/io.c +++ b/src/io.c @@ -356,6 +356,19 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) } } +mrb_value +mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass) +{ + struct RClass *c = mrb_class_ptr(klass); + enum mrb_vtype ttype = MRB_INSTANCE_TT(c); + mrb_value obj; + + /* copied from mrb_instance_alloc() */ + if (ttype == 0) ttype = MRB_TT_OBJECT; + obj = mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c)); + return mrb_io_initialize(mrb, obj); +} + mrb_value mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass) { @@ -847,6 +860,7 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "_sysclose", mrb_io_s_sysclose, MRB_ARGS_REQ(1)); #endif + mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); -- cgit v1.2.3 From e92fd762482eb9f5275f066ae40dfdce201d33ee Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 3 Apr 2015 10:05:09 +0900 Subject: wait for child processes when we close pipes. fixes #37. --- src/io.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/io.c b/src/io.c index 4f7fd25f0..b72eeada6 100644 --- a/src/io.c +++ b/src/io.c @@ -351,6 +351,13 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) } } + if (fptr->pid != 0) { + pid_t pid; + do { + pid = waitpid(fptr->pid, NULL, 0); + } while (pid == -1 && errno == EINTR); + } + if (!noraise && n != 0) { mrb_sys_fail(mrb, "fptr_finalize failed."); } -- cgit v1.2.3 From c0738a74c6e16194723dd2f9ab8032b9f0976414 Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Sun, 5 Apr 2015 17:21:02 -0400 Subject: Excluding wait call for windows --- src/io.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/io.c b/src/io.c index b72eeada6..ede9d1060 100644 --- a/src/io.c +++ b/src/io.c @@ -351,12 +351,14 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) } } +#if !defined(_WIN32) && !defined(_WIN64) if (fptr->pid != 0) { pid_t pid; do { pid = waitpid(fptr->pid, NULL, 0); } while (pid == -1 && errno == EINTR); } +#endif if (!noraise && n != 0) { mrb_sys_fail(mrb, "fptr_finalize failed."); @@ -765,7 +767,7 @@ mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) struct mrb_io *fptr; int ret; - + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); if (fptr->fd < 0) { mrb_raise(mrb, E_IO_ERROR, "closed stream"); @@ -807,7 +809,7 @@ mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) if ((ret & FD_CLOEXEC) != flag) { ret = (ret & ~FD_CLOEXEC) | flag; ret = fcntl(fptr->fd2, F_SETFD, ret); - + if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed"); } } -- cgit v1.2.3 From 36343cf098e2621696a9ae4ad35e7104f5f6383e Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Fri, 17 Apr 2015 15:39:11 -0400 Subject: Correct File::NULL for Windows --- mrblib/file_constants.rb | 2 -- src/file.c | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mrblib/file_constants.rb b/mrblib/file_constants.rb index c2552bf56..a68ee2598 100644 --- a/mrblib/file_constants.rb +++ b/mrblib/file_constants.rb @@ -1,7 +1,5 @@ class File module Constants - NULL = "/dev/null" - RDONLY = 0 WRONLY = 1 RDWR = 2 diff --git a/src/file.c b/src/file.c index c2419c2cc..b6a3c90c7 100644 --- a/src/file.c +++ b/src/file.c @@ -311,4 +311,9 @@ mrb_init_file(mrb_state *mrb) mrb_define_const(mrb, cnst, "LOCK_UN", mrb_fixnum_value(LOCK_UN)); mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB)); mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR)); +#if defined(_WIN32) || defined(_WIN64) + mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, "NUL")); +#else + mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, "/dev/null")); +#endif } -- cgit v1.2.3 From 6d6be18d4eadb6a644c4ea7319b336a5a6fdf52b Mon Sep 17 00:00:00 2001 From: Jared Breeden Date: Fri, 17 Apr 2015 15:45:14 -0400 Subject: Removing redundant platform check --- src/file.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/file.c b/src/file.c index b6a3c90c7..873c3454f 100644 --- a/src/file.c +++ b/src/file.c @@ -24,6 +24,7 @@ #include #include #if defined(_WIN32) || defined(_WIN64) + #define NULL_FILE "NUL" #define UNLINK _unlink #define GETCWD _getcwd #define CHMOD(a, b) 0 @@ -34,6 +35,7 @@ #define realpath(N,R) _fullpath((R),(N),_MAX_PATH) #include #else + #define NULL_FILE "/dev/null" #include #define UNLINK unlink #define GETCWD getcwd @@ -311,9 +313,5 @@ mrb_init_file(mrb_state *mrb) mrb_define_const(mrb, cnst, "LOCK_UN", mrb_fixnum_value(LOCK_UN)); mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB)); mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR)); -#if defined(_WIN32) || defined(_WIN64) - mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, "NUL")); -#else - mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, "/dev/null")); -#endif + mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, NULL_FILE)); } -- cgit v1.2.3 From 8da787be726465b0aab269fb4149ab5c062e7f92 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Thu, 2 Jul 2015 21:02:56 +0200 Subject: Remove mrb_io_s_select typo. Uncovered with a Coverity scan of our project using mruby-io. https://scan8.coverity.com/reports.htm#v26153/p11375/fileInstanceId=6844382&defectInstanceId=2515905&mergedDefectId=121921 --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index ede9d1060..ad3e3c3b7 100644 --- a/src/io.c +++ b/src/io.c @@ -743,7 +743,7 @@ retry: fptr = (struct mrb_io *)mrb_get_datatype(mrb, RARRAY_PTR(except)[i], &mrb_io_type); if (FD_ISSET(fptr->fd, ep)) { mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]); - } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, wp)) { + } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, ep)) { mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]); } } -- cgit v1.2.3 From fe7784efb0c925b2a83ddfccec9db337012580dc Mon Sep 17 00:00:00 2001 From: Terence Lee Date: Tue, 21 Jul 2015 19:38:59 -0500 Subject: support for crossbuild for windows (32 bit and 64 bit) using mingw --- mrbgem.rake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mrbgem.rake b/mrbgem.rake index 77ad101af..8120f7832 100644 --- a/mrbgem.rake +++ b/mrbgem.rake @@ -10,5 +10,7 @@ MRuby::Gem::Specification.new('mruby-io') do |spec| #spec.cc.include_paths += ["C:/Windows/system/include"] spec.linker.library_paths += ["C:/Windows/system"] end - + if build.kind_of?(MRuby::CrossBuild) && %w(x86_64-w64-mingw32 i686-w64-mingw32).include?(build.host_target) + spec.linker.libraries += ['ws2_32'] + end end -- cgit v1.2.3 From ec4982b2d339a2bd4e45adcee1b5d2bb1d890f6f Mon Sep 17 00:00:00 2001 From: Terence Lee Date: Sun, 2 Aug 2015 17:21:08 +0200 Subject: define PATH_SEPARATOR --- src/file.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/file.c b/src/file.c index 873c3454f..10d6b2268 100644 --- a/src/file.c +++ b/src/file.c @@ -47,6 +47,11 @@ #endif #define FILE_SEPARATOR "/" +#if defined(_WIN32) || defined(_WIN64) + #define PATH_SEPARATOR ";" +#else + #define PATH_SEPARATOR ":" +#endif #ifndef LOCK_SH #define LOCK_SH 1 @@ -313,5 +318,7 @@ mrb_init_file(mrb_state *mrb) mrb_define_const(mrb, cnst, "LOCK_UN", mrb_fixnum_value(LOCK_UN)); mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB)); mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR)); + mrb_define_const(mrb, cnst, "PATH_SEPARATOR", mrb_str_new_cstr(mrb, PATH_SEPARATOR)); mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, NULL_FILE)); + } -- cgit v1.2.3 From 2467332c935e10a68db96de71fbf58648a72ebfb Mon Sep 17 00:00:00 2001 From: Joe Kutner Date: Thu, 20 Aug 2015 07:22:48 -0500 Subject: Made FILE_SEPERATOR platform dependent --- src/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/file.c b/src/file.c index 10d6b2268..feb8558ed 100644 --- a/src/file.c +++ b/src/file.c @@ -46,11 +46,12 @@ #include #endif -#define FILE_SEPARATOR "/" #if defined(_WIN32) || defined(_WIN64) #define PATH_SEPARATOR ";" + #define FILE_SEPARATOR "\\" #else #define PATH_SEPARATOR ":" + #define FILE_SEPARATOR "/" #endif #ifndef LOCK_SH -- cgit v1.2.3 From 5fa3c39145d9d8126d0eb9020c6ac660560d32ce Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 27 Aug 2015 09:56:17 +0900 Subject: variables are not used on the platforms lack FD_CLOEXEC. --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 1d2f98f3c..64403a75a 100644 --- a/src/io.c +++ b/src/io.c @@ -128,9 +128,9 @@ mrb_io_flags_to_modenum(mrb_state *mrb, int flags) void mrb_fd_cloexec(mrb_state *mrb, int fd) { +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) int flags, flags2; -#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) flags = fcntl(fd, F_GETFD); if (flags == -1) { mrb_sys_fail(mrb, "fcntl"); -- cgit v1.2.3 From c26f998ed5976c453afc4ba68aa24aaa9d0c0d4e Mon Sep 17 00:00:00 2001 From: takahashim Date: Sun, 27 Sep 2015 00:29:17 +0900 Subject: support IO#<< --- mrblib/io.rb | 5 +++++ test/io.rb | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/mrblib/io.rb b/mrblib/io.rb index c838b96e5..30eb47404 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -108,6 +108,11 @@ class IO raise IOError end + def <<(str) + write(str) + self + end + def eof? return true if @buf && @buf.size > 0 diff --git a/test/io.rb b/test/io.rb index b828fef49..a5ce7e049 100644 --- a/test/io.rb +++ b/test/io.rb @@ -150,6 +150,14 @@ assert('IO#write', '15.2.20.5.20') do true end +assert('IO#<<') do + io = IO.open(IO.sysopen($mrbtest_io_wfname)) + io << "" << "" + assert_equal 0, io.pos + io.close + true +end + assert('IO.for_fd') do fd = IO.sysopen($mrbtest_io_rfname) io = IO.for_fd(fd) -- cgit v1.2.3 From f5560e8f17492f548ffac924e9ff49b713b6bb3b Mon Sep 17 00:00:00 2001 From: takahashim Date: Sun, 27 Sep 2015 01:39:11 +0900 Subject: enable test --- run_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/run_test.rb b/run_test.rb index 444d18fda..83d80294a 100644 --- a/run_test.rb +++ b/run_test.rb @@ -20,6 +20,7 @@ MRuby::Build.new do |conf| conf.gembox 'default' conf.gem :git => 'https://github.com/iij/mruby-env.git' + conf.enable_test conf.gem File.expand_path(File.dirname(__FILE__)) end -- cgit v1.2.3 From 9bbfc38bb4ee3a5f66f82a68542518f397bb9897 Mon Sep 17 00:00:00 2001 From: takahashim Date: Sun, 27 Sep 2015 21:25:06 +0900 Subject: add IO#rewind --- mrblib/io.rb | 4 ++++ test/io.rb | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/mrblib/io.rb b/mrblib/io.rb index 30eb47404..4d2fda5f3 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -141,6 +141,10 @@ class IO seek(i, SEEK_SET) end + def rewind + seek(0, SEEK_SET) + end + def seek(i, whence = SEEK_SET) raise IOError if closed? @pos = sysseek(i, whence) diff --git a/test/io.rb b/test/io.rb index a5ce7e049..a9bdc3e4f 100644 --- a/test/io.rb +++ b/test/io.rb @@ -256,6 +256,17 @@ assert('IO#pos=, IO#seek') do io.closed? end +assert('IO#rewind') do + fd = IO.sysopen $mrbtest_io_rfname + io = IO.new fd + assert_equal 'm', io.getc + assert_equal 1, io.pos + assert_equal 0, io.rewind + assert_equal 0, io.pos + io.close + io.closed? +end + assert('IO#gets') do fd = IO.sysopen $mrbtest_io_rfname io = IO.new fd -- cgit v1.2.3 From 238704592a82654f96906aec0ad6e334380e5bf5 Mon Sep 17 00:00:00 2001 From: "MATSUMOTO, Ryosuke" Date: Mon, 19 Oct 2015 19:24:39 +0900 Subject: Fix buffer overflow of `pos` when file-size is too big --- src/io.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/io.c b/src/io.c index 1d2f98f3c..d9adb2864 100644 --- a/src/io.c +++ b/src/io.c @@ -525,8 +525,7 @@ mrb_value mrb_io_sysseek(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; - int pos; - mrb_int offset, whence = -1; + mrb_int pos, offset, whence = -1; mrb_get_args(mrb, "i|i", &offset, &whence); if (whence < 0) { -- cgit v1.2.3 From cac00353486c7fc3c4addc7a62e817773ad5eae1 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 20 Oct 2015 15:16:46 +0900 Subject: fix typo. --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 515c93edb..f1bc52d83 100644 --- a/src/io.c +++ b/src/io.c @@ -535,7 +535,7 @@ mrb_io_sysseek(mrb_state *mrb, mrb_value io) fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); pos = lseek(fptr->fd, offset, whence); if (pos < 0) { - mrb_raise(mrb, E_IO_ERROR, "sysseek faield"); + mrb_raise(mrb, E_IO_ERROR, "sysseek failed"); } return mrb_fixnum_value(pos); -- cgit v1.2.3 From 21963f8fa1b3ac5c1896fcc13157fdc70b4d9349 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 20 Oct 2015 15:37:05 +0900 Subject: UT for IO#sysseek. --- test/io.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/io.rb b/test/io.rb index a9bdc3e4f..434607959 100644 --- a/test/io.rb +++ b/test/io.rb @@ -426,6 +426,14 @@ assert('IO#close_on_exec') do # end end +assert('IO#sysseek') do + IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| + assert_equal 2, io.sysseek(2) + assert_equal 5, io.sysseek(3, IO::SEEK_CUR) # 2 + 3 => 5 + assert_equal $mrbtest_io_msg.size - 4, io.sysseek(-4, IO::SEEK_END) + end +end + assert('`cmd`') do assert_equal `echo foo`, "foo\n" end -- cgit v1.2.3 From db7d82967944fca2ef3581a5a5d3417c807b8efc Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 20 Oct 2015 15:39:28 +0900 Subject: raise a SystemCallError when lseek(2) fails. --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index f1bc52d83..ae7402b02 100644 --- a/src/io.c +++ b/src/io.c @@ -535,7 +535,7 @@ mrb_io_sysseek(mrb_state *mrb, mrb_value io) fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); pos = lseek(fptr->fd, offset, whence); if (pos < 0) { - mrb_raise(mrb, E_IO_ERROR, "sysseek failed"); + mrb_sys_fail(mrb, "sysseek"); } return mrb_fixnum_value(pos); -- cgit v1.2.3 From 828551f86ce9a2dd0c1a8af39c8ac99ecc0859a0 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 20 Oct 2015 16:03:02 +0900 Subject: off_t can be larger than mrb_int. --- src/io.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/io.c b/src/io.c index ae7402b02..bcc6ea64e 100644 --- a/src/io.c +++ b/src/io.c @@ -525,7 +525,8 @@ mrb_value mrb_io_sysseek(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; - mrb_int pos, offset, whence = -1; + off_t pos; + mrb_int offset, whence = -1; mrb_get_args(mrb, "i|i", &offset, &whence); if (whence < 0) { @@ -534,11 +535,14 @@ mrb_io_sysseek(mrb_state *mrb, mrb_value io) fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); pos = lseek(fptr->fd, offset, whence); - if (pos < 0) { + if (pos == -1) { mrb_sys_fail(mrb, "sysseek"); } - - return mrb_fixnum_value(pos); + if (pos > MRB_INT_MAX) { + return mrb_float_value(mrb, (mrb_float)pos); + } else { + return mrb_fixnum_value(pos); + } } mrb_value -- cgit v1.2.3 From 44473fecdd454574b8cab67da13c2d5bb809bee2 Mon Sep 17 00:00:00 2001 From: takahashim Date: Sat, 21 Nov 2015 22:03:40 +0900 Subject: add File.path --- mrblib/file.rb | 10 ++++++++++ test/file.rb | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/mrblib/file.rb b/mrblib/file.rb index aa0981930..f644ff691 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -170,4 +170,14 @@ class File < IO ext = fname.split('.').last ext.empty? ? '' : ".#{ext}" end + + def self.path(filename) + if filename.kind_of?(String) + filename + elsif filename.respond_to?(:to_path) + filename.to_path + else + raise TypeError, "no implicit conversion of #{filename.class} into String" + end + end end diff --git a/test/file.rb b/test/file.rb index d6f39ceb1..487b54f38 100644 --- a/test/file.rb +++ b/test/file.rb @@ -106,3 +106,12 @@ assert('File.expand_path (with ENV)') do assert_equal "#{ENV['HOME']}/user", File.expand_path("user", ENV['HOME']), "relative with base_dir" end + +assert('File.path') do + assert_equal "", File.path("") + assert_equal "a/b/c", File.path("a/b/c") + assert_equal "a/../b/./c", File.path("a/../b/./c") + assert_raise(TypeError) { File.path(nil) } + assert_raise(TypeError) { File.path(123) } + +end -- cgit v1.2.3 From 2cc674e58e04a0ae403e0429013ef79e129afeb4 Mon Sep 17 00:00:00 2001 From: takahashim Date: Sun, 22 Nov 2015 13:13:52 +0900 Subject: add File.symlink --- src/file.c | 21 +++++++++++++++++++++ test/file.rb | 15 +++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/file.c b/src/file.c index feb8558ed..9054b67aa 100644 --- a/src/file.c +++ b/src/file.c @@ -290,6 +290,26 @@ mrb_file_flock(mrb_state *mrb, mrb_value self) } #endif +static mrb_value +mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) +{ +#if defined(_WIN32) || defined(_WIN64) + mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform"); +#else + mrb_value from, to; + const char *src, *dst; + + mrb_get_args(mrb, "SS", &from, &to); + src = mrb_string_value_cstr(mrb, &from); + dst = mrb_string_value_cstr(mrb, &to); + + if (symlink(src, dst) < 0) { + mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); + } +#endif + return mrb_fixnum_value(0); +} + void mrb_init_file(mrb_state *mrb) { @@ -302,6 +322,7 @@ mrb_init_file(mrb_state *mrb) mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, MRB_ARGS_ANY()); mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY()); mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2)); + mrb_define_class_method(mrb, file, "symlink", mrb_file_s_symlink, MRB_ARGS_REQ(2)); mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, file, "basename", mrb_file_basename, MRB_ARGS_REQ(1)); diff --git a/test/file.rb b/test/file.rb index 487b54f38..ef8be37ec 100644 --- a/test/file.rb +++ b/test/file.rb @@ -115,3 +115,18 @@ assert('File.path') do assert_raise(TypeError) { File.path(123) } end + +assert('File.symlink') do + target_name = "/usr/bin" + symlink_name = "test-bin-dummy" + if !File.exist?(target_name) + skip("target directory of File.symlink is not found") + else + assert_equal 0, File.symlink(target_name, symlink_name) + begin + assert_equal true, File.symlink?(symlink_name) + ensure + File.delete symlink_name + end + end +end -- cgit v1.2.3 From c9a4091b83b06b20d8e9178ce748d5b101925a2e Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 24 Nov 2015 09:54:03 +0900 Subject: arguments can be shared strings. --- src/file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/file.c b/src/file.c index 9054b67aa..7e2b64c3e 100644 --- a/src/file.c +++ b/src/file.c @@ -298,14 +298,16 @@ mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) #else mrb_value from, to; const char *src, *dst; + int ai = mrb_gc_arena_save(mrb); mrb_get_args(mrb, "SS", &from, &to); - src = mrb_string_value_cstr(mrb, &from); - dst = mrb_string_value_cstr(mrb, &to); + src = mrb_str_to_cstr(mrb, from); + dst = mrb_str_to_cstr(mrb, to); if (symlink(src, dst) < 0) { mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); } + mrb_gc_arena_restore(mrb, ai); #endif return mrb_fixnum_value(0); } -- cgit v1.2.3 From a55accd736e13307f7e925af86751ca878be2058 Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 23 Nov 2015 21:58:38 +0900 Subject: Implement IO.pipe --- README.md | 2 +- mrblib/io.rb | 13 +++++++++++ src/io.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/io.rb | 75 ++++++++++++++++++++++++++++++++++++++++++------------------ 4 files changed, 130 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index d7fa6945b..71f3f5090 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ IO, File module for mruby | IO.copy_stream | | | | IO.new, IO.for_fd, IO.open | o | | | IO.foreach | | | -| IO.pipe | | | +| IO.pipe | o | | | IO.popen | o | | | IO.read | o | | | IO.readlines | | | diff --git a/mrblib/io.rb b/mrblib/io.rb index 4d2fda5f3..1742fac32 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -41,6 +41,19 @@ class IO end end + def self.pipe(&block) + if block + begin + r, w = IO._pipe + yield r, w + ensure + r.close unless r.closed? + w.close unless w.closed? + end + else + IO._pipe + end + end def self.read(path, length=nil, offset=nil, opt=nil) if not opt.nil? # 4 arguments diff --git a/src/io.c b/src/io.c index bcc6ea64e..abe7f85c4 100644 --- a/src/io.c +++ b/src/io.c @@ -149,6 +149,32 @@ mrb_fd_cloexec(mrb_state *mrb, int fd) #endif } +static int +mrb_cloexec_pipe(mrb_state *mrb, int fildes[2]) +{ + int ret; + ret = pipe(fildes); + if (ret == -1) + return -1; + mrb_fd_cloexec(mrb, fildes[0]); + mrb_fd_cloexec(mrb, fildes[1]); + return ret; +} + +static int +mrb_pipe(mrb_state *mrb, int pipes[2]) +{ + int ret; + ret = mrb_cloexec_pipe(mrb, pipes); + if (ret == -1) { + if (errno == EMFILE || errno == ENFILE) { + mrb_garbage_collect(mrb); + ret = mrb_cloexec_pipe(mrb, pipes); + } + } + return ret; +} + #ifndef _WIN32 static int mrb_proc_exec(const char *pname) @@ -644,6 +670,42 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) return 0; } +static mrb_value +mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) +{ + mrb_value r = mrb_nil_value(); + mrb_value w = mrb_nil_value(); + struct mrb_io *fptr_r; + struct mrb_io *fptr_w; + int pipes[2]; + + if (mrb_pipe(mrb, pipes) == -1) { + mrb_sys_fail(mrb, "pipe"); + } + + r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); + fptr_r = mrb_io_alloc(mrb); + fptr_r->fd = pipes[0]; + fptr_r->writable = 0; + fptr_r->sync = 0; + DATA_TYPE(r) = &mrb_io_type; + DATA_PTR(r) = fptr_r; + + w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); + fptr_w = mrb_io_alloc(mrb); + fptr_w->fd = pipes[1]; + fptr_w->writable = 1; + fptr_w->sync = 1; + DATA_TYPE(w) = &mrb_io_type; + DATA_PTR(w) = fptr_w; + + return mrb_assoc_new(mrb, r, w); +} + static mrb_value mrb_io_s_select(mrb_state *mrb, mrb_value klass) { @@ -925,6 +987,7 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ mrb_define_method(mrb, io, "sync", mrb_io_sync, MRB_ARGS_NONE()); diff --git a/test/io.rb b/test/io.rb index 434607959..a35d7a074 100644 --- a/test/io.rb +++ b/test/io.rb @@ -402,28 +402,23 @@ assert('IO#close_on_exec') do io.close io.closed? - # # Use below when IO.pipe is implemented. - # begin - # r, w = IO.pipe - # assert_equal(false, r.close_on_exec?) - # r.close_on_exec = true - # assert_equal(true, r.close_on_exec?) - # r.close_on_exec = false - # assert_equal(false, r.close_on_exec?) - # r.close_on_exec = true - # assert_equal(true, r.close_on_exec?) - - # assert_equal(false, w.close_on_exec?) - # w.close_on_exec = true - # assert_equal(true, w.close_on_exec?) - # w.close_on_exec = false - # assert_equal(false, w.close_on_exec?) - # w.close_on_exec = true - # assert_equal(true, w.close_on_exec?) - # ensure - # r.close unless r.closed? - # w.close unless w.closed? - # end + begin + r, w = IO.pipe + assert_equal(true, r.close_on_exec?) + r.close_on_exec = false + assert_equal(false, r.close_on_exec?) + r.close_on_exec = true + assert_equal(true, r.close_on_exec?) + + assert_equal(true, w.close_on_exec?) + w.close_on_exec = false + assert_equal(false, w.close_on_exec?) + w.close_on_exec = true + assert_equal(true, w.close_on_exec?) + ensure + r.close unless r.closed? + w.close unless w.closed? + end end assert('IO#sysseek') do @@ -434,6 +429,42 @@ assert('IO#sysseek') do end end +assert('IO.pipe') do + called = false + IO.pipe do |r, w| + assert_true r.kind_of?(IO) + assert_true w.kind_of?(IO) + assert_false r.closed? + assert_false w.closed? + assert_true FileTest.pipe?(r) + assert_true FileTest.pipe?(w) + assert_nil r.pid + assert_nil w.pid + assert_true 2 < r.fileno + assert_true 2 < w.fileno + assert_true r.fileno != w.fileno + assert_false r.sync + assert_true w.sync + assert_equal 8, w.write('test for') + assert_equal 'test', r.read(4) + assert_equal ' for', r.read(4) + assert_equal 5, w.write(' pipe') + assert_equal nil, w.close + assert_equal ' pipe', r.read + called = true + assert_raise(IOError) { r.write 'test' } + # TODO: + # This assert expect raise IOError but got RuntimeError + # Because mruby-io not have flag for I/O readable + # assert_raise(IOError) { w.read } + end + assert_true called + + assert_nothing_raised do + IO.pipe { |r, w| r.close; w.close } + end +end + assert('`cmd`') do assert_equal `echo foo`, "foo\n" end -- cgit v1.2.3 From 11ffb9385292e7e0144ba78fcc259336437cbe9b Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 24 Nov 2015 17:00:12 +0900 Subject: assert_nothing_raised is not available on mruby 1.0.0. --- test/io.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/io.rb b/test/io.rb index a35d7a074..5104b343c 100644 --- a/test/io.rb +++ b/test/io.rb @@ -1,6 +1,26 @@ ## # IO Test +unless Object.respond_to? :assert_nothing_raised + def assert_nothing_raised(*exp) + ret = true + if $mrbtest_assert + $mrbtest_assert_idx += 1 + msg = exp.last.class == String ? exp.pop : "" + begin + yield + rescue Exception => e + msg = "#{msg} exception raised." + diff = " Class: <#{e.class}>\n" + + " Message: #{e.message}" + $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) + ret = false + end + end + ret + end +end + assert('IO TEST SETUP') do MRubyIOTestUtil.io_test_setup end -- cgit v1.2.3 From 07f1ebd26d03ff1a91d06a6324fc8f9185152180 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 24 Nov 2015 17:09:00 +0900 Subject: symlink(2) returns -1 when it fails. --- src/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/file.c b/src/file.c index 7e2b64c3e..9e1afe688 100644 --- a/src/file.c +++ b/src/file.c @@ -304,7 +304,7 @@ mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) src = mrb_str_to_cstr(mrb, from); dst = mrb_str_to_cstr(mrb, to); - if (symlink(src, dst) < 0) { + if (symlink(src, dst) == -1) { mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); } mrb_gc_arena_restore(mrb, ai); -- cgit v1.2.3 From 07ceb138fae95a2de2147d7cffeff6bd0d6e0c73 Mon Sep 17 00:00:00 2001 From: takahashim Date: Tue, 1 Dec 2015 22:49:11 +0900 Subject: build on Win32 --- src/io.c | 6 +++++- test/mruby_io_test.c | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/io.c b/src/io.c index abe7f85c4..8acf4d597 100644 --- a/src/io.c +++ b/src/io.c @@ -149,6 +149,7 @@ mrb_fd_cloexec(mrb_state *mrb, int fd) #endif } +#ifndef _WIN32 static int mrb_cloexec_pipe(mrb_state *mrb, int fildes[2]) { @@ -175,7 +176,6 @@ mrb_pipe(mrb_state *mrb, int pipes[2]) return ret; } -#ifndef _WIN32 static int mrb_proc_exec(const char *pname) { @@ -670,6 +670,7 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) return 0; } +#ifndef _WIN32 static mrb_value mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) { @@ -705,6 +706,7 @@ mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) return mrb_assoc_new(mrb, r, w); } +#endif static mrb_value mrb_io_s_select(mrb_state *mrb, mrb_value klass) @@ -987,7 +989,9 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); +#ifndef _WIN32 mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE()); +#endif mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ mrb_define_method(mrb, io, "sync", mrb_io_sync, MRB_ARGS_NONE()); diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index f58f9ff8c..98ec54524 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -1,10 +1,17 @@ #include -#include + +#if defined(_WIN32) || defined(_WIN64) + #include + #include +#else + #include + #include + #include +#endif + #include -#include #include #include -#include #include "mruby.h" #include "mruby/array.h" @@ -22,13 +29,18 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) mode_t mask; int fd0, fd1, fd2, fd3; FILE *fp; + +#ifndef _WIN32 struct sockaddr_un sun0; +#endif mask = umask(077); fd0 = mkstemp(rfname); fd1 = mkstemp(wfname); +#ifndef _WIN32 fd2 = mkstemp(symlinkname); fd3 = mkstemp(socketname); +#endif if (fd0 == -1 || fd1 == -1 || fd2 == -1 || fd3 == -1) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file"); return mrb_nil_value(); @@ -56,6 +68,7 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) } fclose(fp); +#ifndef _WIN32 unlink(symlinkname); close(fd2); if (symlink("hoge", symlinkname) == -1) { @@ -74,6 +87,7 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a socket bi"); } close(fd3); +#endif return mrb_true_value(); } @@ -112,9 +126,11 @@ static mrb_value mrb_io_test_file_setup(mrb_state *mrb, mrb_value self) { mrb_value ary = mrb_io_test_io_setup(mrb, self); +#ifndef _WIN32 if (symlink("/usr/bin", "test-bin") == -1) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link"); } +#endif return ary; } -- cgit v1.2.3 From b19c315148cfda6d02b4073b4f741d2e4d5e96a7 Mon Sep 17 00:00:00 2001 From: takahashim Date: Wed, 2 Dec 2015 21:47:46 +0900 Subject: fix tests for Win: use binary mode --- test/mruby_io_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index 98ec54524..2777e605e 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -53,7 +53,7 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_str_new_cstr(mrb, socketname)); mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg)); - fp = fopen(rfname, "w"); + fp = fopen(rfname, "wb"); if (fp == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file"); return mrb_nil_value(); @@ -61,7 +61,7 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) fputs(msg, fp); fclose(fp); - fp = fopen(wfname, "w"); + fp = fopen(wfname, "wb"); if (fp == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file"); return mrb_nil_value(); -- cgit v1.2.3 From 0f5b8b66b0918576b3419360080ebfac272a4ed5 Mon Sep 17 00:00:00 2001 From: takahashim Date: Fri, 4 Dec 2015 13:05:03 +0900 Subject: fix file separator * File::SEPARATOR should be "/" * File::ALT_SEPARATOR should be "\\" or nil. --- src/file.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/file.c b/src/file.c index 9e1afe688..a118cf1f5 100644 --- a/src/file.c +++ b/src/file.c @@ -46,12 +46,13 @@ #include #endif +#define FILE_SEPARATOR "/" + #if defined(_WIN32) || defined(_WIN64) #define PATH_SEPARATOR ";" - #define FILE_SEPARATOR "\\" + #define FILE_ALT_SEPARATOR "\\" #else #define PATH_SEPARATOR ":" - #define FILE_SEPARATOR "/" #endif #ifndef LOCK_SH @@ -343,6 +344,11 @@ mrb_init_file(mrb_state *mrb) mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB)); mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR)); mrb_define_const(mrb, cnst, "PATH_SEPARATOR", mrb_str_new_cstr(mrb, PATH_SEPARATOR)); +#if defined(_WIN32) || defined(_WIN64) + mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_str_new_cstr(mrb, FILE_ALT_SEPARATOR)); +#else + mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_nil_value()); +#endif mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, NULL_FILE)); } -- cgit v1.2.3 From dd754220ce2a53f8cf44362a2b2d1f59f40e62d5 Mon Sep 17 00:00:00 2001 From: takahashim Date: Sun, 6 Dec 2015 00:07:16 +0900 Subject: Fix for windows(mingw) * File.expand_path: support drive letter and ALT_SEPARATOR * File.dirname: support ALT_SEPARATOR * File.basename: ditto. * IO.popen: raise NotImplementedError * IO.pipe: ditto. * `cmd`: ditto. * File#flock: ditto. * FileTest.pipe?: ditto. * FileTest.symlink?: ditto. * FileTest.socket?: ditto. --- mrblib/file.rb | 24 +++++++++++--- mrblib/io.rb | 6 ++++ src/file.c | 43 ++++++++++++++++++------- src/file_test.c | 12 +++++++ test/file.rb | 32 +++++++++++++------ test/file_test.rb | 30 ++++++++++++------ test/io.rb | 94 +++++++++++++++++++++++++++++++------------------------ 7 files changed, 165 insertions(+), 76 deletions(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index f644ff691..86074c3e3 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -89,14 +89,21 @@ class File < IO end expanded_path = concat_path(path, default_dir) + drive_prefix = "" + if File::ALT_SEPARATOR && expanded_path.size > 2 && + ("A".."Z").include?(expanded_path[0].upcase) && expanded_path[1] == ":" + drive_prefix = expanded_path[0, 2] + expanded_path = expanded_path[2, expanded_path.size] + end expand_path_array = [] + if File::ALT_SEPARATOR && expanded_path.include?(File::ALT_SEPARATOR) + expanded_path.gsub!(File::ALT_SEPARATOR, '/') + end while expanded_path.include?('//') expanded_path = expanded_path.gsub('//', '/') end - if expanded_path == "/" - expanded_path - else + if expanded_path != "/" expanded_path.split('/').each do |path_token| if path_token == '..' if expand_path_array.size > 1 @@ -109,8 +116,15 @@ class File < IO end end - expand_path = expand_path_array.join("/") - expand_path.empty? ? '/' : expand_path + expanded_path = expand_path_array.join("/") + if expanded_path.empty? + expanded_path = '/' + end + end + if drive_prefix.empty? + expanded_path + else + drive_prefix + expanded_path.gsub("/", File::ALT_SEPARATOR) end end diff --git a/mrblib/io.rb b/mrblib/io.rb index 1742fac32..755dbbf6d 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -27,6 +27,9 @@ class IO end def self.popen(command, mode = 'r', &block) + if !self.respond_to?(:_popen) + raise NotImplementedError, "popen is not supported on this platform" + end io = self._popen(command, mode) return io unless block @@ -42,6 +45,9 @@ class IO end def self.pipe(&block) + if !self.respond_to?(:_pipe) + raise NotImplementedError, "pipe is not supported on this platform" + end if block begin r, w = IO._pipe diff --git a/src/file.c b/src/file.c index a118cf1f5..84aba39ad 100644 --- a/src/file.c +++ b/src/file.c @@ -130,17 +130,28 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) static mrb_value mrb_file_dirname(mrb_state *mrb, mrb_value klass) { - #if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) || defined(_WIN64) char dname[_MAX_DIR], vname[_MAX_DRIVE]; char buffer[_MAX_DRIVE + _MAX_DIR]; char *path; + size_t ridx; mrb_value s; mrb_get_args(mrb, "S", &s); path = mrb_str_to_cstr(mrb, s); _splitpath((const char*)path, vname, dname, NULL, NULL); snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname); + ridx = strlen(buffer); + if (ridx == 0) { + strncpy(buffer, ".", 2); /* null terminated */ + } else if (ridx > 1) { + ridx--; + while (ridx > 0 && (buffer[ridx] == '/' || buffer[ridx] == '\\')) { + buffer[ridx] = '\0'; /* remove last char */ + ridx--; + } + } return mrb_str_new_cstr(mrb, buffer); - #else +#else char *dname, *path; mrb_value s; mrb_get_args(mrb, "S", &s); @@ -149,25 +160,37 @@ mrb_file_dirname(mrb_state *mrb, mrb_value klass) if ((dname = dirname(path)) == NULL) { mrb_sys_fail(mrb, "dirname"); } - #endif +#endif return mrb_str_new_cstr(mrb, dname); } static mrb_value mrb_file_basename(mrb_state *mrb, mrb_value klass) { - #if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) || defined(_WIN64) char bname[_MAX_DIR]; char extname[_MAX_EXT]; char *path; + size_t ridx; char buffer[_MAX_DIR + _MAX_EXT]; mrb_value s; mrb_get_args(mrb, "S", &s); path = mrb_str_to_cstr(mrb, s); + ridx = strlen(path); + if (ridx > 0) { + ridx--; + while (ridx > 0 && (path[ridx] == '/' || path[ridx] == '\\')) { + path[ridx] = '\0'; + ridx--; + } + if (strncmp(path, "/", 2) == 0) { + return mrb_str_new_cstr(mrb, path); + } + } _splitpath((const char*)path, NULL, NULL, bname, extname); snprintf(buffer, _MAX_DIR + _MAX_EXT, "%s%s", bname, extname); return mrb_str_new_cstr(mrb, buffer); - #else +#else char *bname, *path; mrb_value s; mrb_get_args(mrb, "S", &s); @@ -176,7 +199,7 @@ mrb_file_basename(mrb_state *mrb, mrb_value klass) mrb_sys_fail(mrb, "basename"); } return mrb_str_new_cstr(mrb, bname); - #endif +#endif } static mrb_value @@ -255,12 +278,11 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) #endif } -#ifndef _WIN32 mrb_value mrb_file_flock(mrb_state *mrb, mrb_value self) { -#if defined(sun) - mrb_raise(mrb, E_RUNTIME_ERROR, "flock is not supported on Illumos/Solaris"); +#if defined(_WIN32) || defined(_WIN64) || defined(sun) + mrb_raise(mrb, E_NOTIMP_ERROR, "flock is not supported on Illumos/Solaris/Windows"); #else mrb_int operation; int fd; @@ -289,7 +311,6 @@ mrb_file_flock(mrb_state *mrb, mrb_value self) #endif return mrb_fixnum_value(0); } -#endif static mrb_value mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) @@ -333,9 +354,7 @@ mrb_init_file(mrb_state *mrb) mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, MRB_ARGS_NONE()); mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1)); - #ifndef _WIN32 mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1)); - #endif cnst = mrb_define_module_under(mrb, file, "Constants"); mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH)); diff --git a/src/file_test.c b/src/file_test.c index 6c380c4a5..da2ef77b0 100644 --- a/src/file_test.c +++ b/src/file_test.c @@ -128,6 +128,9 @@ mrb_filetest_s_directory_p(mrb_state *mrb, mrb_value klass) mrb_value mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass) { +#if defined(_WIN32) || defined(_WIN64) + mrb_raise(mrb, E_NOTIMP_ERROR, "pipe is not supported on this platform"); +#else #ifdef S_IFIFO # ifndef S_ISFIFO # define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) @@ -145,6 +148,7 @@ mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass) #endif return mrb_false_value(); +#endif } /* @@ -157,6 +161,9 @@ mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass) mrb_value mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass) { +#if defined(_WIN32) || defined(_WIN64) + mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform"); +#else #ifndef S_ISLNK # ifdef _S_ISLNK # define S_ISLNK(m) _S_ISLNK(m) @@ -184,6 +191,7 @@ mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass) #endif return mrb_false_value(); +#endif } /* @@ -196,6 +204,9 @@ mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass) mrb_value mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass) { +#if defined(_WIN32) || defined(_WIN64) + mrb_raise(mrb, E_NOTIMP_ERROR, "socket is not supported on this platform"); +#else #ifndef S_ISSOCK # ifdef _S_ISSOCK # define S_ISSOCK(m) _S_ISSOCK(m) @@ -223,6 +234,7 @@ mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass) #endif return mrb_false_value(); +#endif } /* diff --git a/test/file.rb b/test/file.rb index ef8be37ec..ebb515cbf 100644 --- a/test/file.rb +++ b/test/file.rb @@ -56,12 +56,16 @@ end assert('IO#flock') do f = File.open $mrbtest_io_rfname - assert_equal(f.flock(File::LOCK_SH), 0) - assert_equal(f.flock(File::LOCK_UN), 0) - assert_equal(f.flock(File::LOCK_EX | File::LOCK_NB), 0) - assert_equal(f.flock(File::LOCK_UN), 0) - f.close - true + begin + assert_equal(f.flock(File::LOCK_SH), 0) + assert_equal(f.flock(File::LOCK_UN), 0) + assert_equal(f.flock(File::LOCK_EX | File::LOCK_NB), 0) + assert_equal(f.flock(File::LOCK_UN), 0) + rescue NotImplementedError => e + skip e.message + ensure + f.close + end end assert('File.join') do @@ -76,8 +80,13 @@ assert('File.join') do end assert('File.realpath') do - usrbin = IO.popen("cd bin; /bin/pwd -P") { |f| f.read.chomp } - assert_equal usrbin, File.realpath("bin") + if File.const_defined?(:ALT_SEPARATOR) && File::ALT_SEPARATOR + readme_path = File._getwd + File::ALT_SEPARATOR + "README.md" + assert_equal readme_path, File.realpath("README.md") + else + usrbin = IO.popen("cd bin; /bin/pwd -P") { |f| f.read.chomp } + assert_equal usrbin, File.realpath("bin") + end end assert('File TEST CLEANUP') do @@ -95,7 +104,12 @@ assert('File.expand_path') do assert_equal "/hoge", File.expand_path("////tmp/..///////hoge") assert_equal "/", File.expand_path("../../../..", "/") - assert_equal "/", File.expand_path(([".."] * 100).join("/")) + if File._getwd[1] == ":" + drive_letter = File._getwd[0] + assert_equal drive_letter + ":\\", File.expand_path(([".."] * 100).join("/")) + else + assert_equal "/", File.expand_path(([".."] * 100).join("/")) + end end assert('File.expand_path (with ENV)') do diff --git a/test/file_test.rb b/test/file_test.rb index 11742f2db..87db67954 100644 --- a/test/file_test.rb +++ b/test/file_test.rb @@ -6,8 +6,8 @@ assert('FileTest TEST SETUP') do end assert("FileTest.directory?") do - assert_equal true, FileTest.directory?("/tmp") - assert_equal false, FileTest.directory?("/bin/sh") + assert_equal true, FileTest.directory?(File.join(File._getwd, "mrblib")) + assert_equal false, FileTest.directory?(File.join(File._getwd, "README.md")) end assert("FileTest.exist?") do @@ -23,14 +23,18 @@ assert("FileTest.exist?") do end assert("FileTest.file?") do - assert_equal false, FileTest.file?("/tmp") - assert_equal true, FileTest.file?("/bin/sh") + assert_equal false, FileTest.file?(File.join(File._getwd, "mrblib")) + assert_equal true, FileTest.file?(File.join(File._getwd, "README.md")) end assert("FileTest.pipe?") do - io = IO.popen("ls") - assert_equal true, FileTest.pipe?(io) - assert_equal false, FileTest.pipe?("/tmp") + begin + assert_equal false, FileTest.pipe?("/tmp") + io = IO.popen("ls") + assert_equal true, FileTest.pipe?(io) + rescue NotImplementedError => e + skip e.message + end end assert('FileTest.size') do @@ -61,11 +65,19 @@ assert("FileTest.size?") do end assert("FileTest.socket?") do - assert_true FileTest.socket?($mrbtest_io_socketname) + begin + assert_true FileTest.socket?($mrbtest_io_socketname) + rescue NotImplementedError => e + skip e.message + end end assert("FileTest.symlink?") do - assert_true FileTest.symlink?($mrbtest_io_symlinkname) + begin + assert_true FileTest.symlink?($mrbtest_io_symlinkname) + rescue NotImplementedError => e + skip e.message + end end assert("FileTest.zero?") do diff --git a/test/io.rb b/test/io.rb index 5104b343c..ee0432b14 100644 --- a/test/io.rb +++ b/test/io.rb @@ -359,15 +359,19 @@ assert('IO#gets - paragraph mode') do end assert('IO.popen') do - io = IO.popen("ls") - assert_true io.close_on_exec? - assert_equal Fixnum, io.pid.class - ls = io.read - assert_equal ls.class, String - assert_include ls, 'AUTHORS' - assert_include ls, 'mrblib' - io.close - io.closed? + begin + io = IO.popen("ls") + assert_true io.close_on_exec? + assert_equal Fixnum, io.pid.class + ls = io.read + assert_equal ls.class, String + assert_include ls, 'AUTHORS' + assert_include ls, 'mrblib' + io.close + io.closed? + rescue NotImplementedError => e + skip e.message + end end assert('IO.read') do @@ -450,43 +454,51 @@ assert('IO#sysseek') do end assert('IO.pipe') do - called = false - IO.pipe do |r, w| - assert_true r.kind_of?(IO) - assert_true w.kind_of?(IO) - assert_false r.closed? - assert_false w.closed? - assert_true FileTest.pipe?(r) - assert_true FileTest.pipe?(w) - assert_nil r.pid - assert_nil w.pid - assert_true 2 < r.fileno - assert_true 2 < w.fileno - assert_true r.fileno != w.fileno - assert_false r.sync - assert_true w.sync - assert_equal 8, w.write('test for') - assert_equal 'test', r.read(4) - assert_equal ' for', r.read(4) - assert_equal 5, w.write(' pipe') - assert_equal nil, w.close - assert_equal ' pipe', r.read - called = true - assert_raise(IOError) { r.write 'test' } - # TODO: - # This assert expect raise IOError but got RuntimeError - # Because mruby-io not have flag for I/O readable - # assert_raise(IOError) { w.read } - end - assert_true called + begin + called = false + IO.pipe do |r, w| + assert_true r.kind_of?(IO) + assert_true w.kind_of?(IO) + assert_false r.closed? + assert_false w.closed? + assert_true FileTest.pipe?(r) + assert_true FileTest.pipe?(w) + assert_nil r.pid + assert_nil w.pid + assert_true 2 < r.fileno + assert_true 2 < w.fileno + assert_true r.fileno != w.fileno + assert_false r.sync + assert_true w.sync + assert_equal 8, w.write('test for') + assert_equal 'test', r.read(4) + assert_equal ' for', r.read(4) + assert_equal 5, w.write(' pipe') + assert_equal nil, w.close + assert_equal ' pipe', r.read + called = true + assert_raise(IOError) { r.write 'test' } + # TODO: + # This assert expect raise IOError but got RuntimeError + # Because mruby-io not have flag for I/O readable + # assert_raise(IOError) { w.read } + end + assert_true called - assert_nothing_raised do - IO.pipe { |r, w| r.close; w.close } + assert_nothing_raised do + IO.pipe { |r, w| r.close; w.close } + end + rescue NotImplementedError => e + skip e.message end end assert('`cmd`') do - assert_equal `echo foo`, "foo\n" + begin + assert_equal `echo foo`, "foo\n" + rescue NotImplementedError => e + skip e.message + end end assert('IO TEST CLEANUP') do -- cgit v1.2.3 From 99e10b8dc44cd7e362f23706cc94a3e0ac840ed7 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 8 Dec 2015 16:44:13 +0900 Subject: File::ALT_SEPARATOR is always defined (some string or nil). --- test/file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/file.rb b/test/file.rb index ebb515cbf..d62077f6e 100644 --- a/test/file.rb +++ b/test/file.rb @@ -80,7 +80,7 @@ assert('File.join') do end assert('File.realpath') do - if File.const_defined?(:ALT_SEPARATOR) && File::ALT_SEPARATOR + if File::ALT_SEPARATOR readme_path = File._getwd + File::ALT_SEPARATOR + "README.md" assert_equal readme_path, File.realpath("README.md") else -- cgit v1.2.3 From 7d6f2beaaafe137358f29bc716f4f9ca14bc6ffd Mon Sep 17 00:00:00 2001 From: Maxim Abramchuk Date: Wed, 20 Jan 2016 13:40:30 +0300 Subject: Add installation instructions --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 71f3f5090..7e6a48f1d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,12 @@ mruby-io IO, File module for mruby +## Installation +Add the line below to your `build_config.rb`: + +``` + conf.gem :github => 'iij/mruby-io' +``` ## Implemented methods -- cgit v1.2.3 From 777cf70cc52e52dcce41585db5b19e997b40e65c Mon Sep 17 00:00:00 2001 From: Eric Hodel Date: Thu, 12 May 2016 16:02:09 -0700 Subject: Include reason in test failure message I am seeing this test fail in some environments but can't determine why. The extra information will help me determine the reason bind(2) is failing. --- test/mruby_io_test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index 2777e605e..fdd20d226 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -1,4 +1,5 @@ #include +#include #if defined(_WIN32) || defined(_WIN64) #include @@ -84,7 +85,9 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) sun0.sun_family = AF_UNIX; snprintf(sun0.sun_path, sizeof(sun0.sun_path), "%s", socketname); if (bind(fd3, (struct sockaddr *)&sun0, sizeof(sun0)) == -1) { - mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a socket bi"); + mrb_raisef(mrb, E_RUNTIME_ERROR, "can't bind AF_UNIX socket to %S: %S", + mrb_str_new_cstr(mrb, sun0.sun_path), + mrb_fixnum_value(errno)); } close(fd3); #endif -- cgit v1.2.3 From 11961b42ac7a15fc59da3acd2dc83935ea879557 Mon Sep 17 00:00:00 2001 From: Eric Hodel Date: Thu, 12 May 2016 17:47:56 -0700 Subject: Create socket in /tmp for security Some systems do not allow UNIX sockets from arbitrary directories. Instead of trying to `#define SOCKET_PATH` correctly I assume the /tmp/ directory is accessible and use it. --- test/mruby_io_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index fdd20d226..ca0f818a1 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -25,7 +25,7 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) char rfname[] = "tmp.mruby-io-test.XXXXXXXX"; char wfname[] = "tmp.mruby-io-test.XXXXXXXX"; char symlinkname[] = "tmp.mruby-io-test.XXXXXXXX"; - char socketname[] = "tmp.mruby-io-test.XXXXXXXX"; + char socketname[] = "/tmp/mruby-io-test.XXXXXXXX"; char msg[] = "mruby io test\n"; mode_t mask; int fd0, fd1, fd2, fd3; -- cgit v1.2.3 From 2af2a4fff838ef7f84a357252ab3afe8d8359b68 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 21 Jun 2016 09:49:34 +0900 Subject: add IO#isatty and IO#tty? --- README.md | 4 ++-- mrblib/io.rb | 1 + src/io.c | 65 ++++++++++++++++++++++++++++++++++-------------------------- test/io.rb | 12 +++++++++++ 4 files changed, 52 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 7e6a48f1d..dd7accd6f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ mruby-io ======== -IO, File module for mruby +`IO` and `File` classes for mruby ## Installation Add the line below to your `build_config.rb`: @@ -62,7 +62,7 @@ Add the line below to your `build_config.rb`: | IO#gets | o | | | IO#internal_encoding | | | | IO#ioctl | | | -| IO#isatty, IO#tty? | | | +| IO#isatty, IO#tty? | o | | | IO#lineno | | | | IO#lineno= | | | | IO#lines | | obsolete | diff --git a/mrblib/io.rb b/mrblib/io.rb index 755dbbf6d..9644c2396 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -367,6 +367,7 @@ class IO end alias_method :to_i, :fileno + alias_method :tty?, :isatty end STDIN = IO.open(0, "r") diff --git a/src/io.c b/src/io.c index 8acf4d597..3f2d5edab 100644 --- a/src/io.c +++ b/src/io.c @@ -40,6 +40,11 @@ #include +static void mrb_io_free(mrb_state *mrb, void *ptr); +struct mrb_data_type mrb_io_type = { "IO", mrb_io_free }; + + +static struct mrb_io *io_get_open_fptr(mrb_state *mrb, mrb_value self); static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr); static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags); static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise); @@ -52,6 +57,18 @@ mrb_module_get(mrb_state *mrb, const char *name) } #endif +static struct mrb_io * +io_get_open_fptr(mrb_state *mrb, mrb_value self) +{ + struct mrb_io *fptr; + + fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); + if (fptr->fd < 0) { + mrb_raise(mrb, E_IO_ERROR, "closed stream."); + } + return fptr; +} + static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) { @@ -205,8 +222,6 @@ mrb_io_free(mrb_state *mrb, void *ptr) } } -struct mrb_data_type mrb_io_type = { "IO", mrb_io_free }; - static struct mrb_io * mrb_io_alloc(mrb_state *mrb) { @@ -424,6 +439,17 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) } } +mrb_value +mrb_io_isatty(mrb_state *mrb, mrb_value self) +{ + struct mrb_io *fptr; + + fptr = io_get_open_fptr(mrb, self); + if (isatty(fptr->fd) == 0) + return mrb_false_value(); + return mrb_true_value(); +} + mrb_value mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass) { @@ -601,13 +627,10 @@ mrb_io_syswrite(mrb_state *mrb, mrb_value io) } mrb_value -mrb_io_close(mrb_state *mrb, mrb_value io) +mrb_io_close(mrb_state *mrb, mrb_value self) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); - if (fptr && fptr->fd < 0) { - mrb_raise(mrb, E_IO_ERROR, "closed stream."); - } + fptr = io_get_open_fptr(mrb, self); fptr_finalize(mrb, fptr, FALSE); return mrb_nil_value(); } @@ -879,16 +902,13 @@ mrb_io_fileno(mrb_state *mrb, mrb_value io) } mrb_value -mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) +mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value self) { #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) struct mrb_io *fptr; int ret; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); - if (fptr->fd < 0) { - mrb_raise(mrb, E_IO_ERROR, "closed stream"); - } + fptr = io_get_open_fptr(mrb, self); if (fptr->fd2 >= 0) { if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed"); @@ -906,18 +926,14 @@ mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) } mrb_value -mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) +mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value self) { #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) struct mrb_io *fptr; int flag, ret; mrb_bool b; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); - if (fptr->fd < 0) { - mrb_raise(mrb, E_IO_ERROR, "closed stream"); - } - + fptr = io_get_open_fptr(mrb, self); mrb_get_args(mrb, "b", &b); flag = b ? FD_CLOEXEC : 0; @@ -951,11 +967,7 @@ mrb_io_set_sync(mrb_state *mrb, mrb_value self) struct mrb_io *fptr; mrb_bool b; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); - if (fptr->fd < 0) { - mrb_raise(mrb, E_IO_ERROR, "closed stream."); - } - + fptr = io_get_open_fptr(mrb, self); mrb_get_args(mrb, "b", &b); fptr->sync = b; return mrb_bool_value(b); @@ -965,11 +977,7 @@ mrb_value mrb_io_sync(mrb_state *mrb, mrb_value self) { struct mrb_io *fptr; - - fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); - if (fptr->fd < 0) { - mrb_raise(mrb, E_IO_ERROR, "closed stream."); - } + fptr = io_get_open_fptr(mrb, self); return mrb_bool_value(fptr->sync); } @@ -994,6 +1002,7 @@ mrb_init_io(mrb_state *mrb) #endif mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ + mrb_define_method(mrb, io, "isatty", mrb_io_isatty, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "sync", mrb_io_sync, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "sync=", mrb_io_set_sync, MRB_ARGS_REQ(1)); mrb_define_method(mrb, io, "sysread", mrb_io_sysread, MRB_ARGS_ANY()); diff --git a/test/io.rb b/test/io.rb index ee0432b14..da94360d7 100644 --- a/test/io.rb +++ b/test/io.rb @@ -262,6 +262,18 @@ assert('IO#_read_buf') do io.closed? end +assert('IO#isatty') do + f1 = File.open("/dev/tty") + f2 = File.open($mrbtest_io_rfname) + + assert_true f1.isatty + assert_false f2.isatty + + f1.close + f2.close + true +end + assert('IO#pos=, IO#seek') do fd = IO.sysopen $mrbtest_io_rfname io = IO.new fd -- cgit v1.2.3 From 93d481d4b49829e37b1f501c7307663c6327dfab Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 22 Jun 2016 10:29:49 +0900 Subject: update $? when IO object is closed. closes #58. --- src/io.c | 37 ++++++++++++++++++++++++++++++++----- test/io.rb | 7 +++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/io.c b/src/io.c index 3f2d5edab..42e9a93a8 100644 --- a/src/io.c +++ b/src/io.c @@ -47,7 +47,7 @@ struct mrb_data_type mrb_io_type = { "IO", mrb_io_free }; static struct mrb_io *io_get_open_fptr(mrb_state *mrb, mrb_value self); static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr); static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags); -static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise); +static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet); #if MRUBY_RELEASE_NO < 10000 static struct RClass * @@ -69,6 +69,29 @@ io_get_open_fptr(mrb_state *mrb, mrb_value self) return fptr; } +#if !defined(_WIN32) && !defined(_WIN64) +static void +io_set_process_status(mrb_state *mrb, pid_t pid, int status) +{ + struct RClass *c_process, *c_status; + mrb_value v; + + c_status = NULL; + if (mrb_class_defined(mrb, "Process")) { + c_process = mrb_class_get(mrb, "Process"); + if (mrb_const_defined(mrb, mrb_obj_value(c_process), mrb_intern_cstr(mrb, "Status"))) { + c_status = mrb_class_get_under(mrb, c_process, "Status"); + } + } + if (c_status != NULL) { + v = mrb_funcall(mrb, mrb_obj_value(c_status), "new", 2, mrb_fixnum_value(pid), mrb_fixnum_value(status)); + } else { + v = mrb_fixnum_value(WEXITSTATUS(status)); + } + mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$?"), v); +} +#endif + static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) { @@ -389,7 +412,7 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) fptr = DATA_PTR(io); if (fptr != NULL) { - fptr_finalize(mrb, fptr, 0); + fptr_finalize(mrb, fptr, TRUE); mrb_free(mrb, fptr); } fptr = mrb_io_alloc(mrb); @@ -404,7 +427,7 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) } static void -fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) +fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet) { int n = 0; @@ -428,13 +451,17 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int noraise) #if !defined(_WIN32) && !defined(_WIN64) if (fptr->pid != 0) { pid_t pid; + int status; do { - pid = waitpid(fptr->pid, NULL, 0); + pid = waitpid(fptr->pid, &status, 0); } while (pid == -1 && errno == EINTR); + if (!quiet && pid == fptr->pid) { + io_set_process_status(mrb, pid, status); + } } #endif - if (!noraise && n != 0) { + if (!quiet && n != 0) { mrb_sys_fail(mrb, "fptr_finalize failed."); } } diff --git a/test/io.rb b/test/io.rb index da94360d7..f0f30e3ce 100644 --- a/test/io.rb +++ b/test/io.rb @@ -372,6 +372,7 @@ end assert('IO.popen') do begin + $? = nil io = IO.popen("ls") assert_true io.close_on_exec? assert_equal Fixnum, io.pid.class @@ -379,7 +380,13 @@ assert('IO.popen') do assert_equal ls.class, String assert_include ls, 'AUTHORS' assert_include ls, 'mrblib' + io.close + if Object.const_defined? :Process + assert_true $?.success? + else + assert_equal 0, $? + end io.closed? rescue NotImplementedError => e skip e.message -- cgit v1.2.3 From 4cac5e9c70e9d73d97b77bc189ce7ac1f585b102 Mon Sep 17 00:00:00 2001 From: ksss Date: Sat, 6 Aug 2016 23:11:31 +0900 Subject: Should use global variable --- mrblib/io.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 9644c2396..e688a32fe 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -380,22 +380,22 @@ $stderr = STDERR module Kernel def print(*args) - STDOUT.print(*args) + $stdout.print(*args) end def puts(*args) - STDOUT.puts(*args) + $stdout.puts(*args) end def printf(*args) - STDOUT.printf(*args) + $stdout.printf(*args) end def gets(*args) - STDIN.gets(*args) + $stdin.gets(*args) end def getc(*args) - STDIN.getc(*args) + $stdin.getc(*args) end end -- cgit v1.2.3 From b462ef450665141a38978d5b31b5550a60db4e6b Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 7 Aug 2016 15:58:39 +0900 Subject: Enable option :in, :out, :err --- mrblib/io.rb | 4 ++-- src/io.c | 13 +++++++++++++ test/io.rb | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 9644c2396..7e6ed9b1d 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -26,11 +26,11 @@ class IO end end - def self.popen(command, mode = 'r', &block) + def self.popen(command, mode = 'r', opts={}, &block) if !self.respond_to?(:_popen) raise NotImplementedError, "popen is not supported on this platform" end - io = self._popen(command, mode) + io = self._popen(command, mode, opts) return io unless block begin diff --git a/src/io.c b/src/io.c index 42e9a93a8..f842ceb85 100644 --- a/src/io.c +++ b/src/io.c @@ -270,6 +270,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) mrb_value cmd, io, result; mrb_value mode = mrb_str_new_cstr(mrb, "r"); mrb_value opt = mrb_hash_new(mrb); + mrb_value opt_in, opt_out, opt_err; struct mrb_io *fptr; const char *pname; @@ -315,6 +316,18 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) result = mrb_nil_value(); switch (pid = fork()) { case 0: /* child */ + opt_in = mrb_funcall(mrb, opt, "[]", 1, mrb_symbol_value(mrb_intern_lit(mrb, "in"))); + opt_out = mrb_funcall(mrb, opt, "[]", 1, mrb_symbol_value(mrb_intern_lit(mrb, "out"))); + opt_err = mrb_funcall(mrb, opt, "[]", 1, mrb_symbol_value(mrb_intern_lit(mrb, "err"))); + if (!mrb_nil_p(opt_in)) { + dup2(mrb_fixnum(mrb_io_fileno(mrb, opt_in)), 0); + } + if (!mrb_nil_p(opt_out)) { + dup2(mrb_fixnum(mrb_io_fileno(mrb, opt_out)), 1); + } + if (!mrb_nil_p(opt_err)) { + dup2(mrb_fixnum(mrb_io_fileno(mrb, opt_err)), 2); + } if (flags & FMODE_READABLE) { close(pr[0]); if (pr[1] != 1) { diff --git a/test/io.rb b/test/io.rb index f0f30e3ce..6e1bcb247 100644 --- a/test/io.rb +++ b/test/io.rb @@ -393,6 +393,43 @@ assert('IO.popen') do end end +assert('IO.popen with in option') do + begin + IO.pipe do |r, w| + w.write 'hello' + w.close + assert_equal "hello", IO.popen("cat", "r", in: r) { |i| i.read } + assert_equal "", r.read + end + rescue NotImplementedError => e + skip e.message + end +end + +assert('IO.popen with out option') do + begin + IO.pipe do |r, w| + IO.popen("echo 'hello'", "w", out: w) {} + w.close + assert_equal "hello\n", r.read + end + rescue NotImplementedError => e + skip e.message + end +end + +assert('IO.popen with err option') do + begin + IO.pipe do |r, w| + assert_equal "", IO.popen("echo 'hello' 1>&2", "r", err: w) { |i| i.read } + w.close + assert_equal "hello\n", r.read + end + rescue NotImplementedError => e + skip e.message + end +end + assert('IO.read') do # empty file fd = IO.sysopen $mrbtest_io_wfname, "w" -- cgit v1.2.3 From d2c1f4d10b29040aad3fbf38b2b27fe46e145e63 Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 7 Aug 2016 22:18:08 +0900 Subject: Enable Fixnum option --- src/io.c | 40 ++++++++++++++++++++++++++++++---------- test/io.rb | 1 + 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/io.c b/src/io.c index f842ceb85..264ded8ad 100644 --- a/src/io.c +++ b/src/io.c @@ -264,13 +264,32 @@ mrb_io_alloc(mrb_state *mrb) #endif #ifndef _WIN32 +static int +option_to_fd(mrb_state *mrb, mrb_value obj, const char *key) +{ + mrb_value opt = mrb_funcall(mrb, obj, "[]", 1, mrb_symbol_value(mrb_intern_static(mrb, key, strlen(key)))); + if (mrb_nil_p(opt)) { + return -1; + } + + switch (mrb_type(opt)) { + case MRB_TT_DATA: /* IO */ + return mrb_fixnum(mrb_io_fileno(mrb, opt)); + case MRB_TT_FIXNUM: + return mrb_fixnum(opt); + default: + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong exec redirect action"); + break; + } + return -1; /* never reached */ +} + mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { mrb_value cmd, io, result; mrb_value mode = mrb_str_new_cstr(mrb, "r"); mrb_value opt = mrb_hash_new(mrb); - mrb_value opt_in, opt_out, opt_err; struct mrb_io *fptr; const char *pname; @@ -279,6 +298,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) int pw[2] = { -1, -1 }; int doexec; int saved_errno; + int opt_in, opt_out, opt_err; mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); @@ -287,6 +307,9 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); doexec = (strcmp("-", pname) != 0); + opt_in = option_to_fd(mrb, opt, "in"); + opt_out = option_to_fd(mrb, opt, "out"); + opt_err = option_to_fd(mrb, opt, "err"); if (flags & FMODE_READABLE) { if (pipe(pr) == -1) { @@ -316,17 +339,14 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) result = mrb_nil_value(); switch (pid = fork()) { case 0: /* child */ - opt_in = mrb_funcall(mrb, opt, "[]", 1, mrb_symbol_value(mrb_intern_lit(mrb, "in"))); - opt_out = mrb_funcall(mrb, opt, "[]", 1, mrb_symbol_value(mrb_intern_lit(mrb, "out"))); - opt_err = mrb_funcall(mrb, opt, "[]", 1, mrb_symbol_value(mrb_intern_lit(mrb, "err"))); - if (!mrb_nil_p(opt_in)) { - dup2(mrb_fixnum(mrb_io_fileno(mrb, opt_in)), 0); + if (opt_in != -1) { + dup2(opt_in, 0); } - if (!mrb_nil_p(opt_out)) { - dup2(mrb_fixnum(mrb_io_fileno(mrb, opt_out)), 1); + if (opt_out != -1) { + dup2(opt_out, 1); } - if (!mrb_nil_p(opt_err)) { - dup2(mrb_fixnum(mrb_io_fileno(mrb, opt_err)), 2); + if (opt_err != -1) { + dup2(opt_err, 2); } if (flags & FMODE_READABLE) { close(pr[0]); diff --git a/test/io.rb b/test/io.rb index 6e1bcb247..1b0a2d52e 100644 --- a/test/io.rb +++ b/test/io.rb @@ -401,6 +401,7 @@ assert('IO.popen with in option') do assert_equal "hello", IO.popen("cat", "r", in: r) { |i| i.read } assert_equal "", r.read end + assert_raise(ArgumentError) { IO.popen("hello", "r", in: Object.new) } rescue NotImplementedError => e skip e.message end -- cgit v1.2.3 From 024b09de0c3bf9019bf31ccaa4cd4e150b0113da Mon Sep 17 00:00:00 2001 From: Carlo - PERI Date: Tue, 9 Aug 2016 11:23:49 +0200 Subject: Apparently, in mruby-process gem, Process is now a Module, not a Class --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 264ded8ad..c9b1a8eb6 100644 --- a/src/io.c +++ b/src/io.c @@ -78,7 +78,7 @@ io_set_process_status(mrb_state *mrb, pid_t pid, int status) c_status = NULL; if (mrb_class_defined(mrb, "Process")) { - c_process = mrb_class_get(mrb, "Process"); + c_process = mrb_module_get(mrb, "Process"); if (mrb_const_defined(mrb, mrb_obj_value(c_process), mrb_intern_cstr(mrb, "Status"))) { c_status = mrb_class_get_under(mrb, c_process, "Status"); } -- cgit v1.2.3 From 7c9d941003b48d3551b28879598b3329c3b5d98b Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 11 Sep 2016 17:00:19 +0900 Subject: Show value of expect and actual each assertion --- test/file.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/file.rb b/test/file.rb index d62077f6e..029454ea5 100644 --- a/test/file.rb +++ b/test/file.rb @@ -69,14 +69,14 @@ assert('IO#flock') do end assert('File.join') do - File.join() == "" and - File.join("a") == "a" and - File.join("/a") == "/a" and - File.join("a/") == "a/" and - File.join("a", "b", "c") == "a/b/c" and - File.join("/a", "b", "c") == "/a/b/c" and - File.join("a", "b", "c/") == "a/b/c/" and - File.join("a/", "/b/", "/c") == "a/b/c" + assert_equal "", File.join() + assert_equal "a", File.join("a") + assert_equal "/a", File.join("/a") + assert_equal "a/", File.join("a/") + assert_equal "a/b/c", File.join("a", "b", "c") + assert_equal "/a/b/c", File.join("/a", "b", "c") + assert_equal "a/b/c/", File.join("a", "b", "c/") + assert_equal "a/b/c", File.join("a/", "/b/", "/c") end assert('File.realpath') do -- cgit v1.2.3 From ff845be72cc146dc8c16d408a5694e6587de5957 Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 11 Sep 2016 17:02:35 +0900 Subject: Support Array argument --- mrblib/file.rb | 61 +++++++++++++++++++++++++++++++++++----------------------- test/file.rb | 2 ++ 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index 86074c3e3..f84bd0ed3 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -19,34 +19,47 @@ class File < IO end def self.join(*names) - if names.size == 0 - "" - elsif names.size == 1 - names[0] - else - if names[0][-1] == File::SEPARATOR - s = names[0][0..-2] - else - s = names[0].dup - end - (1..names.size-2).each { |i| - t = names[i] - if t[0] == File::SEPARATOR and t[-1] == File::SEPARATOR - t = t[1..-2] - elsif t[0] == File::SEPARATOR - t = t[1..-1] - elsif t[-1] == File::SEPARATOR - t = t[0..-2] + return "" if names.empty? + + names.map! do |name| + case name + when String + name + when Array + if names == name + raise ArgumentError, "recursive array" end - s += File::SEPARATOR + t if t != "" - } - if names[-1][0] == File::SEPARATOR - s += File::SEPARATOR + names[-1][1..-1] + join(*name) else - s += File::SEPARATOR + names[-1] + raise TypeError, "no implicit conversion of #{name.class} into String" end - s end + + return names[0] if names.size == 1 + + if names[0][-1] == File::SEPARATOR + s = names[0][0..-2] + else + s = names[0].dup + end + + (1..names.size-2).each { |i| + t = names[i] + if t[0] == File::SEPARATOR and t[-1] == File::SEPARATOR + t = t[1..-2] + elsif t[0] == File::SEPARATOR + t = t[1..-1] + elsif t[-1] == File::SEPARATOR + t = t[0..-2] + end + s += File::SEPARATOR + t if t != "" + } + if names[-1][0] == File::SEPARATOR + s += File::SEPARATOR + names[-1][1..-1] + else + s += File::SEPARATOR + names[-1] + end + s end def self.expand_path(path, default_dir = '.') diff --git a/test/file.rb b/test/file.rb index 029454ea5..48a6eea9d 100644 --- a/test/file.rb +++ b/test/file.rb @@ -77,6 +77,8 @@ assert('File.join') do assert_equal "/a/b/c", File.join("/a", "b", "c") assert_equal "a/b/c/", File.join("a", "b", "c/") assert_equal "a/b/c", File.join("a/", "/b/", "/c") + assert_equal "a/b/c", File.join(["a", "b", "c"]) + assert_equal "a/b/c", File.join("a", ["b", ["c"]]) end assert('File.realpath') do -- cgit v1.2.3 From 2229a2aa0fcd76bd5498417aca934d6ec7a211ef Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 30 Sep 2016 16:27:11 +0900 Subject: reimplement #eof. fixes #66. --- mrblib/io.rb | 27 ++++++--------------------- test/io.rb | 25 ++++++++++++++++++++----- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 4bcf4f800..8408aea87 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -133,20 +133,12 @@ class IO end def eof? - return true if @buf && @buf.size > 0 - - ret = false - char = '' - begin - char = sysread(1) - rescue EOFError => e - ret = true - ensure - _ungets(char) + buf = _read_buf + return buf.size == 0 + rescue EOFError + return true end - - ret end alias_method :eof, :eof? @@ -176,24 +168,17 @@ class IO @buf = sysread(BUF_SIZE) end - def _ungets(substr) + def ungetc(substr) raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String) - raise IOError if @pos == 0 || @pos.nil? @pos -= substr.size if @buf.empty? - @buf = substr + @buf = substr.dup else @buf = substr + @buf end nil end - def ungetc(char) - raise IOError if @pos == 0 || @pos.nil? - _ungets(char) - nil - end - def read(length = nil) unless length.nil? unless length.is_a? Fixnum diff --git a/test/io.rb b/test/io.rb index 1b0a2d52e..c3f78da7e 100644 --- a/test/io.rb +++ b/test/io.rb @@ -70,14 +70,29 @@ end #assert('IO#each_line', '15.2.20.5.5') do assert('IO#eof?', '15.2.20.5.6') do + if false # XXX: not implemented yet + io = IO.new(IO.sysopen($mrbtest_io_wfname, 'w'), 'w') + assert_raise(IOError) do + io.eof? + end + end + + # empty file + io = IO.open(IO.sysopen($mrbtest_io_wfname, 'w'), 'w') + io.close + io = IO.open(IO.sysopen($mrbtest_io_wfname, 'r'), 'r') + assert_true io.eof? + io.close + + # nonempty file io = IO.new(IO.sysopen($mrbtest_io_rfname)) - $mrbtest_io_msg.each_char { |ch| - # XXX - #assert_false io.eof? - io.getc - } + assert_false io.eof? + io.readchar + assert_false io.eof? + io.read assert_true io.eof? io.close + true end -- cgit v1.2.3 From f6a82772e6f857856edb37fcb43a892b6022780f Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 30 Sep 2016 17:10:55 +0900 Subject: eof? should raise an IOError if it is not opened for reading. --- include/mruby/ext/io.h | 3 ++- mrblib/io.rb | 1 + src/io.c | 16 ++++++++++++++++ test/io.rb | 9 ++++----- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/include/mruby/ext/io.h b/include/mruby/ext/io.h index 3107f1053..8f412fc02 100644 --- a/include/mruby/ext/io.h +++ b/include/mruby/ext/io.h @@ -13,7 +13,8 @@ struct mrb_io { int fd; /* file descriptor, or -1 */ int fd2; /* file descriptor to write if it's different from fd, or -1 */ int pid; /* child's pid (for pipes) */ - unsigned int writable:1, + unsigned int readable:1, + writable:1, sync:1; }; diff --git a/mrblib/io.rb b/mrblib/io.rb index 8408aea87..0b10c82aa 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -133,6 +133,7 @@ class IO end def eof? + _check_readable begin buf = _read_buf return buf.size == 0 diff --git a/src/io.c b/src/io.c index c9b1a8eb6..f942d564c 100644 --- a/src/io.c +++ b/src/io.c @@ -254,6 +254,7 @@ mrb_io_alloc(mrb_state *mrb) fptr->fd = -1; fptr->fd2 = -1; fptr->pid = 0; + fptr->readable = 0; fptr->writable = 0; fptr->sync = 0; return fptr; @@ -394,6 +395,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) fptr->fd = fd; fptr->fd2 = write_fd; fptr->pid = pid; + fptr->readable = ((flags & FMODE_READABLE) != 0); fptr->writable = ((flags & FMODE_WRITABLE) != 0); fptr->sync = 0; @@ -454,6 +456,7 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) DATA_PTR(io) = fptr; fptr->fd = fd; + fptr->readable = ((flags & FMODE_READABLE) != 0); fptr->writable = ((flags & FMODE_WRITABLE) != 0); fptr->sync = 0; return io; @@ -499,6 +502,16 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet) } } +mrb_value +mrb_io_check_readable(mrb_state *mrb, mrb_value self) +{ + struct mrb_io *fptr = io_get_open_fptr(mrb, self); + if (! fptr->readable) { + mrb_raise(mrb, E_IO_ERROR, "not opened for reading"); + } + return mrb_nil_value(); +} + mrb_value mrb_io_isatty(mrb_state *mrb, mrb_value self) { @@ -772,6 +785,7 @@ mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr_r = mrb_io_alloc(mrb); fptr_r->fd = pipes[0]; + fptr_r->readable = 1; fptr_r->writable = 0; fptr_r->sync = 0; DATA_TYPE(r) = &mrb_io_type; @@ -782,6 +796,7 @@ mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr_w = mrb_io_alloc(mrb); fptr_w->fd = pipes[1]; + fptr_w->readable = 0; fptr_w->writable = 1; fptr_w->sync = 1; DATA_TYPE(w) = &mrb_io_type; @@ -1062,6 +1077,7 @@ mrb_init_io(mrb_state *mrb) #endif mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ + mrb_define_method(mrb, io, "_check_readable", mrb_io_check_readable, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "isatty", mrb_io_isatty, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "sync", mrb_io_sync, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "sync=", mrb_io_set_sync, MRB_ARGS_REQ(1)); diff --git a/test/io.rb b/test/io.rb index c3f78da7e..e1ea4640e 100644 --- a/test/io.rb +++ b/test/io.rb @@ -70,12 +70,11 @@ end #assert('IO#each_line', '15.2.20.5.5') do assert('IO#eof?', '15.2.20.5.6') do - if false # XXX: not implemented yet - io = IO.new(IO.sysopen($mrbtest_io_wfname, 'w'), 'w') - assert_raise(IOError) do - io.eof? - end + io = IO.new(IO.sysopen($mrbtest_io_wfname, 'w'), 'w') + assert_raise(IOError) do + io.eof? end + io.close # empty file io = IO.open(IO.sysopen($mrbtest_io_wfname, 'w'), 'w') -- cgit v1.2.3 From b5e2dc90975e5304f7b1220656d6a9138b51cdee Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 13 Oct 2016 16:57:38 +0900 Subject: raise an exception when we cannot close "fd" but can close "fd2". --- src/io.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/io.c b/src/io.c index f942d564c..3177ec050 100644 --- a/src/io.c +++ b/src/io.c @@ -465,23 +465,26 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet) { - int n = 0; + int saved_errno = 0; if (fptr == NULL) { return; } if (fptr->fd > 2) { - n = close(fptr->fd); - if (n == 0) { - fptr->fd = -1; + if (close(fptr->fd) == -1) { + saved_errno = errno; } + fptr->fd = -1; } + if (fptr->fd2 > 2) { - n = close(fptr->fd2); - if (n == 0) { - fptr->fd2 = -1; + if (close(fptr->fd2) == -1) { + if (saved_errno == 0) { + saved_errno = errno; + } } + fptr->fd2 = -1; } #if !defined(_WIN32) && !defined(_WIN64) @@ -494,10 +497,13 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet) if (!quiet && pid == fptr->pid) { io_set_process_status(mrb, pid, status); } + fptr->pid = 0; + /* Note: we don't raise an exception when waitpid(3) fails */ } #endif - if (!quiet && n != 0) { + if (!quiet && saved_errno != 0) { + errno = saved_errno; mrb_sys_fail(mrb, "fptr_finalize failed."); } } -- cgit v1.2.3 From 905203ef5edc269aca4178a084f3c62fbafaec82 Mon Sep 17 00:00:00 2001 From: Kohei Suzuki Date: Sat, 26 Nov 2016 14:18:28 +0900 Subject: Add explicit cast from void* to struct mrb_io* For compatibility with C++. --- src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 3177ec050..dd030b87a 100644 --- a/src/io.c +++ b/src/io.c @@ -445,7 +445,7 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); - fptr = DATA_PTR(io); + fptr = (struct mrb_io *)DATA_PTR(io); if (fptr != NULL) { fptr_finalize(mrb, fptr, TRUE); mrb_free(mrb, fptr); -- cgit v1.2.3 From 698378f076380b9668b3da9d1e1d0617073f917b Mon Sep 17 00:00:00 2001 From: Kohei Suzuki Date: Fri, 16 Dec 2016 01:20:08 +0900 Subject: Add File.chmod --- README.md | 2 +- src/file.c | 20 ++++++++++++++++++++ test/file.rb | 9 +++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dd7accd6f..604361f25 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ Add the line below to your `build_config.rb`: | File.basename | o | | | File.blockdev? | | FileTest | | File.chardev? | | FileTest | -| File.chmod | | | +| File.chmod | o | | | File.chown | | | | File.ctime | | | | File.delete, File.unlink | o | | diff --git a/src/file.c b/src/file.c index 84aba39ad..2131db654 100644 --- a/src/file.c +++ b/src/file.c @@ -334,6 +334,25 @@ mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) return mrb_fixnum_value(0); } +static mrb_value +mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { + mrb_int mode; + mrb_int argc, i; + mrb_value *filenames; + int ai = mrb_gc_arena_save(mrb); + + mrb_get_args(mrb, "i*", &mode, &filenames, &argc); + for (i = 0; i < argc; i++) { + char *path = mrb_str_to_cstr(mrb, filenames[i]); + if (CHMOD(path, mode) == -1) { + mrb_sys_fail(mrb, path); + } + } + + mrb_gc_arena_restore(mrb, ai); + return mrb_fixnum_value(argc); +} + void mrb_init_file(mrb_state *mrb) { @@ -347,6 +366,7 @@ mrb_init_file(mrb_state *mrb) mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY()); mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2)); mrb_define_class_method(mrb, file, "symlink", mrb_file_s_symlink, MRB_ARGS_REQ(2)); + mrb_define_class_method(mrb, file, "chmod", mrb_file_s_chmod, MRB_ARGS_REQ(1) | MRB_ARGS_REST()); mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, file, "basename", mrb_file_basename, MRB_ARGS_REQ(1)); diff --git a/test/file.rb b/test/file.rb index 48a6eea9d..f5607bbaa 100644 --- a/test/file.rb +++ b/test/file.rb @@ -146,3 +146,12 @@ assert('File.symlink') do end end end + +assert('File.chmod') do + File.open('chmod-test', 'w') {} + begin + assert_equal 1, File.chmod(0400, 'chmod-test') + ensure + File.delete('chmod-test') + end +end -- cgit v1.2.3 From d1c48192cbff3cdc9168854c115d2d421068fb01 Mon Sep 17 00:00:00 2001 From: Kohei Suzuki Date: Sat, 17 Dec 2016 15:00:04 +0900 Subject: Add File.readlink --- README.md | 2 +- src/file.c | 31 +++++++++++++++++++++++++++++++ test/file.rb | 16 ++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 604361f25..e007393a9 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ Add the line below to your `build_config.rb`: | File.pipe? | o | FileTest | | File.readable? | | FileTest | | File.readable_real? | | FileTest | -| File.readlink | | | +| File.readlink | o | | | File.realdirpath | | | | File.realpath | o | | | File.rename | o | | diff --git a/src/file.c b/src/file.c index 2131db654..a1c965638 100644 --- a/src/file.c +++ b/src/file.c @@ -353,6 +353,36 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { return mrb_fixnum_value(argc); } +static mrb_value +mrb_file_s_readlink(mrb_state *mrb, mrb_value klass) { +#if defined(_WIN32) || defined(_WIN64) + mrb_raise(mrb, E_NOTIMP_ERROR, "readlink is not supported on this platform"); + return mrb_nil_value(); // unreachable +#else + char *path, *buf; + size_t bufsize = 100; + ssize_t rc; + mrb_value ret; + int ai = mrb_gc_arena_save(mrb); + + mrb_get_args(mrb, "z", &path); + + buf = mrb_malloc(mrb, bufsize); + while ((rc = readlink(path, buf, bufsize)) == bufsize && rc != -1) { + bufsize *= 2; + buf = mrb_realloc(mrb, buf, bufsize); + } + if (rc == -1) { + mrb_sys_fail(mrb, path); + } + ret = mrb_str_new(mrb, buf, rc); + mrb_free(mrb, buf); + + mrb_gc_arena_restore(mrb, ai); + return ret; +#endif +} + void mrb_init_file(mrb_state *mrb) { @@ -367,6 +397,7 @@ mrb_init_file(mrb_state *mrb) mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2)); mrb_define_class_method(mrb, file, "symlink", mrb_file_s_symlink, MRB_ARGS_REQ(2)); mrb_define_class_method(mrb, file, "chmod", mrb_file_s_chmod, MRB_ARGS_REQ(1) | MRB_ARGS_REST()); + mrb_define_class_method(mrb, file, "readlink", mrb_file_s_readlink, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, file, "basename", mrb_file_basename, MRB_ARGS_REQ(1)); diff --git a/test/file.rb b/test/file.rb index f5607bbaa..58c16bbfe 100644 --- a/test/file.rb +++ b/test/file.rb @@ -91,6 +91,22 @@ assert('File.realpath') do end end +assert("File.readlink") do + begin + assert_equal 'hoge', File.readlink($mrbtest_io_symlinkname) + rescue NotImplementedError => e + skip e.message + end +end + +assert("File.readlink fails with non-symlink") do + begin + assert_raise(RuntimeError) { File.readlink($mrbtest_io_rfname) } + rescue NotImplementedError => e + skip e.message + end +end + assert('File TEST CLEANUP') do assert_nil MRubyIOTestUtil.io_test_cleanup end -- cgit v1.2.3 From b31b8022db8a471167f1789909a38c54d573a741 Mon Sep 17 00:00:00 2001 From: Kohei Suzuki Date: Sat, 17 Dec 2016 16:48:02 +0900 Subject: Fix memory leak in error case --- src/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/file.c b/src/file.c index a1c965638..054cd6417 100644 --- a/src/file.c +++ b/src/file.c @@ -373,6 +373,7 @@ mrb_file_s_readlink(mrb_state *mrb, mrb_value klass) { buf = mrb_realloc(mrb, buf, bufsize); } if (rc == -1) { + mrb_free(mrb, buf); mrb_sys_fail(mrb, path); } ret = mrb_str_new(mrb, buf, rc); -- cgit v1.2.3 From 1fac605e3f483228d21505cbc391a86bc72235f9 Mon Sep 17 00:00:00 2001 From: masahino Date: Sat, 24 Dec 2016 23:32:44 +0900 Subject: Add pointer casting --- src/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/file.c b/src/file.c index 054cd6417..9a0bed5a6 100644 --- a/src/file.c +++ b/src/file.c @@ -367,10 +367,10 @@ mrb_file_s_readlink(mrb_state *mrb, mrb_value klass) { mrb_get_args(mrb, "z", &path); - buf = mrb_malloc(mrb, bufsize); + buf = (char *)mrb_malloc(mrb, bufsize); while ((rc = readlink(path, buf, bufsize)) == bufsize && rc != -1) { bufsize *= 2; - buf = mrb_realloc(mrb, buf, bufsize); + buf = (char *)mrb_realloc(mrb, buf, bufsize); } if (rc == -1) { mrb_free(mrb, buf); -- cgit v1.2.3 From caab1c203cc996c521fc7115aab0991e1e53e05c Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 8 Feb 2017 18:31:50 +0900 Subject: define IO#hash to override Enumerable#hash. fixes #73. Current implementation of Enumerable#hash calls #each to collect hash values of enumerated objects (then calculates the hash value of the Enumerable object). But IO#each is a method to read lines. It is not expected that IO#hash reads all lines from the IO object. Or even worse, program waits for the IO object to be readable if it is a socket or something cannot be read immediately. --- mrblib/io.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mrblib/io.rb b/mrblib/io.rb index 0b10c82aa..08f9180dd 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -114,6 +114,12 @@ class IO self end + def hash + # We must define IO#hash here because IO includes Enumerable and + # Enumerable#hash will call IO#read... + self.__id__ + end + def write(string) str = string.is_a?(String) ? string : string.to_s return str.size unless str.size > 0 -- cgit v1.2.3 From 86d58a2d3727f556e6e6ce10d170b6170911a263 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 10 Feb 2017 11:22:52 +0900 Subject: File class does not have to include Enumerable. Because IO class, which is the superclass of File class, includes it. --- mrblib/file.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/mrblib/file.rb b/mrblib/file.rb index f84bd0ed3..514efc1c6 100644 --- a/mrblib/file.rb +++ b/mrblib/file.rb @@ -1,6 +1,4 @@ class File < IO - include Enumerable - class FileError < Exception; end class NoFileError < FileError; end class UnableToStat < FileError; end -- cgit v1.2.3 From 74fe87c28916763e08cfeb6fb43049428fe71e1a Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 17 Feb 2017 10:33:11 +0900 Subject: Add a travis-ci badge. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e007393a9..0f50e24ec 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ mruby-io ======== +[![Build Status](https://travis-ci.org/iij/mruby-io.svg?branch=master)](https://travis-ci.org/iij/mruby-io) + `IO` and `File` classes for mruby -- cgit v1.2.3 From 3ae5fea2b8d288e5a0c6c25077495bf87c2e4487 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Tue, 28 Feb 2017 12:10:51 +0900 Subject: run mrbtest outside of source tree. --- test/file.rb | 23 +++++++++++++++++++---- test/file_test.rb | 18 ++++++++++++++---- test/io.rb | 13 +++++++------ test/mruby_io_test.c | 33 ++++++++++++++++++++++++++++++++- 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/test/file.rb b/test/file.rb index 58c16bbfe..941e91ac4 100644 --- a/test/file.rb +++ b/test/file.rb @@ -86,14 +86,20 @@ assert('File.realpath') do readme_path = File._getwd + File::ALT_SEPARATOR + "README.md" assert_equal readme_path, File.realpath("README.md") else - usrbin = IO.popen("cd bin; /bin/pwd -P") { |f| f.read.chomp } - assert_equal usrbin, File.realpath("bin") + dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX") + begin + dir1 = File.realpath($mrbtest_io_rfname) + dir2 = File.realpath("./#{dir}//./../#{$mrbtest_io_symlinkname}") + assert_equal dir1, dir2 + ensure + MRubyIOTestUtil.rmdir dir + end end end assert("File.readlink") do begin - assert_equal 'hoge', File.readlink($mrbtest_io_symlinkname) + assert_equal $mrbtest_io_rfname, File.readlink($mrbtest_io_symlinkname) rescue NotImplementedError => e skip e.message end @@ -101,7 +107,16 @@ end assert("File.readlink fails with non-symlink") do begin - assert_raise(RuntimeError) { File.readlink($mrbtest_io_rfname) } + assert_raise(RuntimeError) { + begin + File.readlink($mrbtest_io_rfname) + rescue => e + if Object.const_defined?(:SystemCallError) and e.kind_of?(SystemCallError) + raise RuntimeError, "SystemCallError converted to RuntimeError" + end + raise e + end + } rescue NotImplementedError => e skip e.message end diff --git a/test/file_test.rb b/test/file_test.rb index 87db67954..2c831f0d5 100644 --- a/test/file_test.rb +++ b/test/file_test.rb @@ -6,8 +6,13 @@ assert('FileTest TEST SETUP') do end assert("FileTest.directory?") do - assert_equal true, FileTest.directory?(File.join(File._getwd, "mrblib")) - assert_equal false, FileTest.directory?(File.join(File._getwd, "README.md")) + dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX") + begin + assert_true FileTest.directory?(dir) + assert_false FileTest.directory?($mrbtest_io_rfname) + ensure + MRubyIOTestUtil.rmdir dir + end end assert("FileTest.exist?") do @@ -23,8 +28,13 @@ assert("FileTest.exist?") do end assert("FileTest.file?") do - assert_equal false, FileTest.file?(File.join(File._getwd, "mrblib")) - assert_equal true, FileTest.file?(File.join(File._getwd, "README.md")) + dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX") + begin + assert_true FileTest.file?($mrbtest_io_rfname) + assert_false FileTest.file?(dir) + ensure + MRubyIOTestUtil.rmdir dir + end end assert("FileTest.pipe?") do diff --git a/test/io.rb b/test/io.rb index e1ea4640e..955481b9f 100644 --- a/test/io.rb +++ b/test/io.rb @@ -387,13 +387,13 @@ end assert('IO.popen') do begin $? = nil - io = IO.popen("ls") + io = IO.popen("echo mruby-io") assert_true io.close_on_exec? assert_equal Fixnum, io.pid.class - ls = io.read - assert_equal ls.class, String - assert_include ls, 'AUTHORS' - assert_include ls, 'mrblib' + + out = io.read + assert_equal out.class, String + assert_include out, 'mruby-io' io.close if Object.const_defined? :Process @@ -401,7 +401,8 @@ assert('IO.popen') do else assert_equal 0, $? end - io.closed? + + assert_true io.closed? rescue NotImplementedError => e skip e.message end diff --git a/test/mruby_io_test.c b/test/mruby_io_test.c index ca0f818a1..ffaa27ff4 100644 --- a/test/mruby_io_test.c +++ b/test/mruby_io_test.c @@ -16,6 +16,7 @@ #include "mruby.h" #include "mruby/array.h" +#include "mruby/error.h" #include "mruby/string.h" #include "mruby/variable.h" @@ -72,7 +73,7 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) #ifndef _WIN32 unlink(symlinkname); close(fd2); - if (symlink("hoge", symlinkname) == -1) { + if (symlink(rfname, symlinkname) == -1) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link"); } @@ -147,6 +148,34 @@ mrb_io_test_file_cleanup(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } +static mrb_value +mrb_io_test_mkdtemp(mrb_state *mrb, mrb_value klass) +{ + mrb_value str; + char *cp; + + mrb_get_args(mrb, "S", &str); + cp = mrb_str_to_cstr(mrb, str); + if (mkdtemp(cp) == NULL) { + mrb_sys_fail(mrb, "mkdtemp"); + } + return mrb_str_new_cstr(mrb, cp); +} + +static mrb_value +mrb_io_test_rmdir(mrb_state *mrb, mrb_value klass) +{ + mrb_value str; + char *cp; + + mrb_get_args(mrb, "S", &str); + cp = mrb_str_to_cstr(mrb, str); + if (rmdir(cp) == -1) { + mrb_sys_fail(mrb, "rmdir"); + } + return mrb_true_value(); +} + void mrb_mruby_io_gem_test(mrb_state* mrb) { @@ -157,4 +186,6 @@ mrb_mruby_io_gem_test(mrb_state* mrb) mrb_define_class_method(mrb, io_test, "file_test_setup", mrb_io_test_file_setup, MRB_ARGS_NONE()); mrb_define_class_method(mrb, io_test, "file_test_cleanup", mrb_io_test_file_cleanup, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, io_test, "mkdtemp", mrb_io_test_mkdtemp, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, io_test, "rmdir", mrb_io_test_rmdir, MRB_ARGS_REQ(1)); } -- cgit v1.2.3 From 311f4a230fe8904ebfebb166e9887496ee26b3e1 Mon Sep 17 00:00:00 2001 From: Yuji Yamano Date: Mon, 24 Apr 2017 02:40:01 -0400 Subject: Make backquote work with the latest mruby. Fixed #75 --- mrblib/kernel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb index 484b50160..373b76f98 100644 --- a/mrblib/kernel.rb +++ b/mrblib/kernel.rb @@ -1,5 +1,5 @@ module Kernel - def self.`(cmd) + def `(cmd) IO.popen(cmd) { |io| io.read } end -- cgit v1.2.3 From 6836f424c5ff95d0114a426010b22254804bc9a3 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Fri, 19 May 2017 17:14:43 +0900 Subject: "open" error message should include pathname. fixes #77. --- src/io.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index dd030b87a..51a659f0e 100644 --- a/src/io.c +++ b/src/io.c @@ -556,6 +556,7 @@ mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass) int mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode) { + mrb_value emsg; int fd, retry = FALSE; #ifdef O_CLOEXEC @@ -576,7 +577,10 @@ reopen: goto reopen; } } - mrb_sys_fail(mrb, "open"); + + emsg = mrb_format(mrb, "open %S", mrb_str_new_cstr(mrb, pathname)); + mrb_str_modify(mrb, mrb_str_ptr(emsg)); + mrb_sys_fail(mrb, RSTRING_PTR(emsg)); } if (fd <= 2) { -- cgit v1.2.3 From c43795c6648546eecf92e22150b7e478e63e1a31 Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 21 May 2017 16:58:57 +0900 Subject: Should raise SyscallError on IO#syswrite instead of IOError --- mrblib/io.rb | 9 ++------- src/io.c | 3 +++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 08f9180dd..694fdb0c9 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -123,14 +123,9 @@ class IO def write(string) str = string.is_a?(String) ? string : string.to_s return str.size unless str.size > 0 - len = syswrite(str) - if len != -1 - @pos += len - return len - end - - raise IOError + @pos += len + len end def <<(str) diff --git a/src/io.c b/src/io.c index 51a659f0e..452a61a3f 100644 --- a/src/io.c +++ b/src/io.c @@ -705,6 +705,9 @@ mrb_io_syswrite(mrb_state *mrb, mrb_value io) fd = fptr->fd2; } length = write(fd, RSTRING_PTR(buf), RSTRING_LEN(buf)); + if (length == -1) { + mrb_sys_fail(mrb, 0); + } return mrb_fixnum_value(length); } -- cgit v1.2.3 From 844b2c368fc4bf852ea1a5f24731ae4bdd6b2331 Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 21 May 2017 22:52:52 +0900 Subject: IO#sysread with 0 always return empty string --- src/io.c | 3 +++ test/io.rb | 1 + 2 files changed, 4 insertions(+) diff --git a/src/io.c b/src/io.c index 51a659f0e..2a24b18a4 100644 --- a/src/io.c +++ b/src/io.c @@ -625,6 +625,9 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) if (maxlen < 0) { return mrb_nil_value(); } + else if (maxlen == 0) { + return mrb_str_new(mrb, NULL, maxlen); + } if (mrb_nil_p(buf)) { buf = mrb_str_new(mrb, NULL, maxlen); diff --git a/test/io.rb b/test/io.rb index 955481b9f..5a95961f3 100644 --- a/test/io.rb +++ b/test/io.rb @@ -234,6 +234,7 @@ assert('IO.sysopen, IO#sysread') do io.sysread(10000) end io.close + assert_equal "", io.sysread(0) io.closed? end -- cgit v1.2.3 From 86edc9ab8541d15b470dd4fe0bac1e136c2ffced Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 21 May 2017 22:54:46 +0900 Subject: IO#sysread should raise IOError when closed --- src/io.c | 2 +- test/io.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 2a24b18a4..f15f182f2 100644 --- a/src/io.c +++ b/src/io.c @@ -636,7 +636,7 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) buf = mrb_str_resize(mrb, buf, maxlen); } - fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + fptr = (struct mrb_io *)io_get_open_fptr(mrb, io); ret = read(fptr->fd, RSTRING_PTR(buf), maxlen); switch (ret) { case 0: /* EOF */ diff --git a/test/io.rb b/test/io.rb index 5a95961f3..02ab038bb 100644 --- a/test/io.rb +++ b/test/io.rb @@ -235,6 +235,7 @@ assert('IO.sysopen, IO#sysread') do end io.close assert_equal "", io.sysread(0) + assert_raise(IOError) { io.sysread(1) } io.closed? end -- cgit v1.2.3 From 0bbd60b52348a9c1938d8cce7a1d5aea996e7e1e Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 21 May 2017 22:55:28 +0900 Subject: IO#sysread should raise error when invalid pos --- src/io.c | 2 +- test/io.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index f15f182f2..7a1121338 100644 --- a/src/io.c +++ b/src/io.c @@ -623,7 +623,7 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) mrb_get_args(mrb, "i|S", &maxlen, &buf); if (maxlen < 0) { - return mrb_nil_value(); + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative expanding string size"); } else if (maxlen == 0) { return mrb_str_new(mrb, NULL, maxlen); diff --git a/test/io.rb b/test/io.rb index 02ab038bb..9ce8985f7 100644 --- a/test/io.rb +++ b/test/io.rb @@ -236,6 +236,7 @@ assert('IO.sysopen, IO#sysread') do io.close assert_equal "", io.sysread(0) assert_raise(IOError) { io.sysread(1) } + assert_raise(ArgumentError) { io.sysread(-1) } io.closed? end -- cgit v1.2.3 From a3a4f4d061ed4fc1debbee0fe172a786c7c152d5 Mon Sep 17 00:00:00 2001 From: ksss Date: Sat, 27 May 2017 13:29:38 +0900 Subject: IO#sysread Check for readable --- src/io.c | 3 +++ test/io.rb | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/io.c b/src/io.c index 6d1b39cc5..e0de0ca36 100644 --- a/src/io.c +++ b/src/io.c @@ -637,6 +637,9 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) } fptr = (struct mrb_io *)io_get_open_fptr(mrb, io); + if (!fptr->readable) { + mrb_raise(mrb, E_IO_ERROR, "not opened for reading"); + } ret = read(fptr->fd, RSTRING_PTR(buf), maxlen); switch (ret) { case 0: /* EOF */ diff --git a/test/io.rb b/test/io.rb index 9ce8985f7..ee4309b57 100644 --- a/test/io.rb +++ b/test/io.rb @@ -238,6 +238,11 @@ assert('IO.sysopen, IO#sysread') do assert_raise(IOError) { io.sysread(1) } assert_raise(ArgumentError) { io.sysread(-1) } io.closed? + + fd = IO.sysopen $mrbtest_io_wfname, "w" + io = IO.new fd, "w" + assert_raise(IOError) { io.sysread(1) } + io.close end assert('IO.sysopen, IO#syswrite') do -- cgit v1.2.3 From 3a73a5849388fe908af7131804f9fc7f55472651 Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Wed, 7 Jun 2017 11:36:37 +0900 Subject: mruby 1.2.0 assumes test blocks return their results. master does not. --- test/io.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/io.rb b/test/io.rb index ee4309b57..b654ff213 100644 --- a/test/io.rb +++ b/test/io.rb @@ -243,6 +243,7 @@ assert('IO.sysopen, IO#sysread') do io = IO.new fd, "w" assert_raise(IOError) { io.sysread(1) } io.close + true end assert('IO.sysopen, IO#syswrite') do -- cgit v1.2.3 From 27f422880fa501a16642e0499b8140c074b5269b Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 11 Jun 2017 23:05:58 +0900 Subject: To accurate `pos` pos shouldn't cache because it's not controllable --- mrblib/io.rb | 28 ++++++++-------------------- src/io.c | 4 ---- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 694fdb0c9..d9dcaaec9 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -124,7 +124,6 @@ class IO str = string.is_a?(String) ? string : string.to_s return str.size unless str.size > 0 len = syswrite(str) - @pos += len len end @@ -146,7 +145,7 @@ class IO def pos raise IOError if closed? - @pos + sysseek(0, SEEK_CUR) - @buf.length end alias_method :tell, :pos @@ -160,7 +159,7 @@ class IO def seek(i, whence = SEEK_SET) raise IOError if closed? - @pos = sysseek(i, whence) + sysseek(i, whence) @buf = '' 0 end @@ -172,7 +171,6 @@ class IO def ungetc(substr) raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String) - @pos -= substr.size if @buf.empty? @buf = substr.dup else @@ -195,7 +193,6 @@ class IO end array = [] - start_pos = @pos while 1 begin _read_buf @@ -204,15 +201,12 @@ class IO break end - if length && (@pos - start_pos + @buf.size) >= length - len = length - (@pos - start_pos) - array.push @buf[0, len] - @pos += len - @buf = @buf[len, @buf.size - len] + if length && length <= @buf.size + array.push @buf[0, length] + @buf = @buf[length, @buf.size - length] break else array.push @buf - @pos += @buf.size @buf = '' end end @@ -240,7 +234,6 @@ class IO end array = [] - start_pos = @pos while 1 begin _read_buf @@ -249,21 +242,17 @@ class IO break end - if limit && (@pos - start_pos + @buf.size) >= limit - len = limit - (@pos - start_pos) - array.push @buf[0, len] - @pos += len - @buf = @buf[len, @buf.size - len] + if limit && limit <= @buf.size + array.push @buf[0, limit] + @buf = @buf[limit, @buf.size - limit] break elsif idx = @buf.index(rs) len = idx + rs.size array.push @buf[0, len] - @pos += len @buf = @buf[len, @buf.size - len] break else array.push @buf - @pos += @buf.size @buf = '' end end @@ -285,7 +274,6 @@ class IO _read_buf c = @buf[0] @buf = @buf[1, @buf.size] - @pos += 1 c end diff --git a/src/io.c b/src/io.c index e0de0ca36..992801a62 100644 --- a/src/io.c +++ b/src/io.c @@ -389,7 +389,6 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) } mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr = mrb_io_alloc(mrb); fptr->fd = fd; @@ -443,7 +442,6 @@ mrb_io_initialize(mrb_state *mrb, mrb_value io) flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr = (struct mrb_io *)DATA_PTR(io); if (fptr != NULL) { @@ -801,7 +799,6 @@ mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr_r = mrb_io_alloc(mrb); fptr_r->fd = pipes[0]; fptr_r->readable = 1; @@ -812,7 +809,6 @@ mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0)); fptr_w = mrb_io_alloc(mrb); fptr_w->fd = pipes[1]; fptr_w->readable = 0; -- cgit v1.2.3 From 1ebe1c8b1f11d1c2975c4370a4fd3c566132c9d7 Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 12 Jun 2017 09:32:56 +0900 Subject: Support outbuf argument for IO#read --- mrblib/io.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 694fdb0c9..4262504f2 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -181,7 +181,7 @@ class IO nil end - def read(length = nil) + def read(length = nil, outbuf = "") unless length.nil? unless length.is_a? Fixnum raise TypeError.new "can't convert #{length.class} into Integer" @@ -217,7 +217,12 @@ class IO end end - array && array.join + if array.nil? + outbuf.replace("") + nil + else + outbuf.replace(array.join) + end end def readline(arg = $/, limit = nil) -- cgit v1.2.3 From 051d7bc8dbfca584789ae8e9c1c393aea3aa72b7 Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 12 Jun 2017 09:50:51 +0900 Subject: Reseek when write --- mrblib/io.rb | 4 ++++ test/io.rb | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/mrblib/io.rb b/mrblib/io.rb index 694fdb0c9..3ef9c7b5d 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -123,6 +123,10 @@ class IO def write(string) str = string.is_a?(String) ? string : string.to_s return str.size unless str.size > 0 + if 0 < @buf.length + # reset real pos ignore buf + seek(pos, SEEK_SET) + end len = syswrite(str) @pos += len len diff --git a/test/io.rb b/test/io.rb index b654ff213..f1dd7afe8 100644 --- a/test/io.rb +++ b/test/io.rb @@ -181,6 +181,16 @@ assert('IO#write', '15.2.20.5.20') do io = IO.open(IO.sysopen($mrbtest_io_wfname)) assert_equal 0, io.write("") io.close + + io = IO.open(IO.sysopen($mrbtest_io_wfname, "r+"), "r+") + assert_equal 7, io.write("abcdefg") + io.rewind + assert_equal "ab", io.read(2) + assert_equal 3, io.write("123") + io.rewind + assert_equal "ab123fg", io.read + io.close + true end -- cgit v1.2.3 From 3642fe40131220520e961157fa501ee1adf2ebca Mon Sep 17 00:00:00 2001 From: Christopher Aue Date: Tue, 13 Jun 2017 21:40:36 +0200 Subject: fixed #87: IO#read(n) with n > IO::BUF_SIZE --- mrblib/io.rb | 10 ++++++---- test/io.rb | 7 +++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index 3ea839379..f538af490 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -205,10 +205,12 @@ class IO break end - if length && length <= @buf.size - array.push @buf[0, length] - @buf = @buf[length, @buf.size - length] - break + if length + consume = (length <= @buf.size) ? length : @buf.size + array.push @buf[0, consume] + @buf = @buf[consume, @buf.size - consume] + length -= consume + break if length == 0 else array.push @buf @buf = '' diff --git a/test/io.rb b/test/io.rb index f1dd7afe8..5a6dbf146 100644 --- a/test/io.rb +++ b/test/io.rb @@ -140,6 +140,13 @@ assert('IO#read', '15.2.20.5.14') do end end +assert "IO#read(n) with n > IO::BUF_SIZE" do + r,w = IO.pipe + n = IO::BUF_SIZE+1 + w.write 'a'*n + assert_equal r.read(n), 'a'*n +end + assert('IO#readchar', '15.2.20.5.15') do # almost same as IO#getc IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| -- cgit v1.2.3 From 04774e5bf26b10150504635e68202a3965e2253b Mon Sep 17 00:00:00 2001 From: Tomoyuki Sahara Date: Thu, 15 Jun 2017 11:00:26 +0900 Subject: remove unused exception variables. --- mrblib/io.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mrblib/io.rb b/mrblib/io.rb index f538af490..02c8141c5 100644 --- a/mrblib/io.rb +++ b/mrblib/io.rb @@ -200,7 +200,7 @@ class IO while 1 begin _read_buf - rescue EOFError => e + rescue EOFError array = nil if array.empty? and (not length.nil?) and length != 0 break end @@ -248,7 +248,7 @@ class IO while 1 begin _read_buf - rescue EOFError => e + rescue EOFError array = nil if array.empty? break end @@ -276,7 +276,7 @@ class IO def gets(*args) begin readline(*args) - rescue EOFError => e + rescue EOFError nil end end @@ -291,7 +291,7 @@ class IO def getc begin readchar - rescue EOFError => e + rescue EOFError nil end end -- cgit v1.2.3 From 4c255c77399789324e5c4d72787d87ac1fcc49dd Mon Sep 17 00:00:00 2001 From: Vladimir Dementyev Date: Thu, 5 Oct 2017 14:40:43 +0300 Subject: Handle shared/frozen strings in IO#sysread See https://github.com/mruby/mruby/commit/7edbe428caca6814841195a3f2720745cf04353e --- src/io.c | 5 +++++ test/io.rb | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/io.c b/src/io.c index 992801a62..6f52daf4a 100644 --- a/src/io.c +++ b/src/io.c @@ -630,8 +630,13 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) if (mrb_nil_p(buf)) { buf = mrb_str_new(mrb, NULL, maxlen); } + + mrb_str_modify(mrb, RSTRING(buf)); + if (RSTRING_LEN(buf) != maxlen) { buf = mrb_str_resize(mrb, buf, maxlen); + } else { + mrb_str_modify(mrb, RSTRING(buf)); } fptr = (struct mrb_io *)io_get_open_fptr(mrb, io); diff --git a/test/io.rb b/test/io.rb index 5a6dbf146..df646977a 100644 --- a/test/io.rb +++ b/test/io.rb @@ -250,6 +250,11 @@ assert('IO.sysopen, IO#sysread') do io.sysread(10000) io.sysread(10000) end + + assert_raise RuntimeError do + io.sysread(5, "abcde".freeze) + end + io.close assert_equal "", io.sysread(0) assert_raise(IOError) { io.sysread(1) } -- cgit v1.2.3 From 43795cb1f1d3b15c005532a43f9e47f11acd5476 Mon Sep 17 00:00:00 2001 From: Vladimir Dementyev Date: Thu, 5 Oct 2017 15:22:57 +0300 Subject: Remove useless mrb_str_modify --- src/io.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/io.c b/src/io.c index 6f52daf4a..8792bb2aa 100644 --- a/src/io.c +++ b/src/io.c @@ -631,8 +631,6 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io) buf = mrb_str_new(mrb, NULL, maxlen); } - mrb_str_modify(mrb, RSTRING(buf)); - if (RSTRING_LEN(buf) != maxlen) { buf = mrb_str_resize(mrb, buf, maxlen); } else { -- cgit v1.2.3 From 0d92431061322e10cd118b895af8fd94675fd865 Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 12 Oct 2017 15:23:52 +0900 Subject: make the behavior consistent with MRI --- src/file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/file.c b/src/file.c index 9a0bed5a6..0f7674d77 100644 --- a/src/file.c +++ b/src/file.c @@ -119,9 +119,11 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) src = mrb_string_value_cstr(mrb, &from); dst = mrb_string_value_cstr(mrb, &to); if (rename(src, dst) < 0) { +#if defined(_WIN32) || defined(_WIN64) if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) { return mrb_fixnum_value(0); } +#endif mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); } return mrb_fixnum_value(0); -- cgit v1.2.3