diff options
Diffstat (limited to 'mrbgems/mruby-io/mrblib/io.rb')
| -rw-r--r-- | mrbgems/mruby-io/mrblib/io.rb | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/mrbgems/mruby-io/mrblib/io.rb b/mrbgems/mruby-io/mrblib/io.rb new file mode 100644 index 000000000..02c8141c5 --- /dev/null +++ b/mrbgems/mruby-io/mrblib/io.rb @@ -0,0 +1,387 @@ +## +# 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(*args, &block) + io = self.new(*args) + + 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', opts={}, &block) + if !self.respond_to?(:_popen) + raise NotImplementedError, "popen is not supported on this platform" + end + io = self._popen(command, mode, opts) + return io unless block + + begin + yield io + ensure + begin + io.close unless io.closed? + rescue IOError + # nothing + end + end + 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 + 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 + 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). + raise IOError, "closed stream" if self.closed? + 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 + if 0 < @buf.length + # reset real pos ignore buf + seek(pos, SEEK_SET) + end + len = syswrite(str) + len + end + + def <<(str) + write(str) + self + end + + def eof? + _check_readable + begin + buf = _read_buf + return buf.size == 0 + rescue EOFError + return true + end + end + alias_method :eof, :eof? + + def pos + raise IOError if closed? + sysseek(0, SEEK_CUR) - @buf.length + end + alias_method :tell, :pos + + def pos=(i) + seek(i, SEEK_SET) + end + + def rewind + seek(0, SEEK_SET) + end + + def seek(i, whence = SEEK_SET) + raise IOError if closed? + sysseek(i, whence) + @buf = '' + 0 + end + + def _read_buf + return @buf if @buf && @buf.size > 0 + @buf = sysread(BUF_SIZE) + end + + def ungetc(substr) + raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String) + if @buf.empty? + @buf = substr.dup + else + @buf = substr + @buf + end + nil + end + + def read(length = nil, outbuf = "") + 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 + + array = [] + while 1 + begin + _read_buf + rescue EOFError + array = nil if array.empty? and (not length.nil?) and length != 0 + break + end + + 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 = '' + end + end + + if array.nil? + outbuf.replace("") + nil + else + outbuf.replace(array.join) + end + 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 + + array = [] + while 1 + begin + _read_buf + rescue EOFError + array = nil if array.empty? + break + end + + 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] + @buf = @buf[len, @buf.size - len] + break + else + array.push @buf + @buf = '' + end + end + + raise EOFError.new "end of file reached" if array.nil? + + array.join + end + + def gets(*args) + begin + readline(*args) + rescue EOFError + nil + end + end + + def readchar + _read_buf + c = @buf[0] + @buf = @buf[1, @buf.size] + c + end + + def getc + begin + readchar + rescue EOFError + 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 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 + end + + alias_method :to_i, :fileno + alias_method :tty?, :isatty +end + +STDIN = IO.open(0, "r") +STDOUT = IO.open(1, "w") +STDERR = IO.open(2, "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 |
