mirror of
https://github.com/zhigang1992/RubyMotion.git
synced 2026-03-30 17:43:26 +08:00
856 lines
20 KiB
Ruby
856 lines
20 KiB
Ruby
# MacRuby implementation of stringio.
|
|
#
|
|
# This file is covered by the Ruby license. See COPYING for more details.
|
|
#
|
|
# Copyright (C) 2012, The MacRuby Team. All rights reserved.
|
|
# Copyright (C) 2009-2011, Apple Inc. All rights reserved.
|
|
|
|
class StringIO
|
|
|
|
attr_reader :string, :pos
|
|
|
|
# strio.lineno -> integer
|
|
#
|
|
# Returns the current line number in *strio*. The stringio must be
|
|
# opened for reading. +lineno+ counts the number of times +gets+ is
|
|
# called, rather than the number of newlines encountered. The two
|
|
# values will differ if +gets+ is called with a separator other than
|
|
# newline. See also the <code>$.</code> variable.
|
|
#
|
|
#
|
|
# strio.lineno = integer -> integer
|
|
#
|
|
# Manually sets the current line number to the given value.
|
|
# <code>$.</code> is updated only on the next read.
|
|
#
|
|
attr_accessor :lineno
|
|
|
|
include Enumerable
|
|
|
|
# StringIO.open(string=""[, mode]) {|strio| ...}
|
|
#
|
|
# Equivalent to StringIO.new except that when it is called with a block, it
|
|
# yields with the new instance and closes it, and returns the result which
|
|
# returned from the block.
|
|
#
|
|
def self.open(*args)
|
|
obj = new(*args)
|
|
|
|
if block_given?
|
|
begin
|
|
yield obj
|
|
ensure
|
|
obj.close
|
|
obj.instance_variable_set(:@string, nil)
|
|
obj
|
|
end
|
|
else
|
|
obj
|
|
end
|
|
end
|
|
|
|
# StringIO.new(string=""[, mode])
|
|
#
|
|
# Creates new StringIO instance from with _string_ and _mode_.
|
|
#
|
|
def initialize(string = String.new, mode = nil)
|
|
@string = string.to_str
|
|
@pos = 0
|
|
@lineno = 0
|
|
define_mode(mode)
|
|
|
|
raise Errno::EACCES if (@writable && string.frozen?)
|
|
self
|
|
end
|
|
|
|
def initialize_copy(from)
|
|
from = from.to_strio
|
|
self.taint if from.tainted?
|
|
|
|
@string = from.instance_variable_get(:@string).dup
|
|
# mode
|
|
@append = from.instance_variable_get(:@append)
|
|
@readable = from.instance_variable_get(:@readable)
|
|
@writable = from.instance_variable_get(:@writable)
|
|
|
|
@pos = from.instance_variable_get(:@pos)
|
|
@lineno = from.instance_variable_get(:@lineno)
|
|
|
|
self
|
|
end
|
|
|
|
# strio.reopen(other_StrIO) -> strio
|
|
# strio.reopen(string, mode) -> strio
|
|
#
|
|
# Reinitializes *strio* with the given <i>other_StrIO</i> or _string_
|
|
# and _mode_ (see StringIO#new).
|
|
#
|
|
def reopen(str=nil, mode=nil)
|
|
if str == nil && mode == nil
|
|
mode = 'w+'
|
|
elsif !str.kind_of?(String) && mode == nil
|
|
raise TypeError unless str.respond_to?(:to_strio)
|
|
return initialize_copy(str)
|
|
else
|
|
raise TypeError unless str.respond_to?(:to_str)
|
|
@string = str.to_str
|
|
end
|
|
|
|
define_mode(mode)
|
|
@pos = 0
|
|
@lineno = 0
|
|
|
|
self
|
|
end
|
|
|
|
# strio.string = string -> string
|
|
#
|
|
# Changes underlying String object, the subject of IO.
|
|
#
|
|
def string=(str)
|
|
@string = str.to_str
|
|
@pos = 0
|
|
@lineno = 0
|
|
end
|
|
|
|
# strio.rewind -> 0
|
|
#
|
|
# Positions *strio* to the beginning of input, resetting
|
|
# +lineno+ to zero.
|
|
#
|
|
def rewind
|
|
@pos = 0
|
|
@lineno = 0
|
|
end
|
|
|
|
# strio.read([length [, buffer]]) -> string, buffer, or nil
|
|
#
|
|
# See IO#read.
|
|
#
|
|
def read(length = nil, buffer = String.new)
|
|
raise IOError, "not opened for reading" unless @readable
|
|
raise TypeError unless buffer.respond_to?(:to_str)
|
|
buffer = buffer.to_str
|
|
|
|
if length.nil?
|
|
return buffer.replace("") if self.eof?
|
|
buffer.replace(@string[@pos..-1])
|
|
@pos = @string.size
|
|
else
|
|
raise TypeError unless length.respond_to?(:to_int)
|
|
length = length.to_int
|
|
raise ArgumentError if length < 0
|
|
|
|
if length == 0
|
|
buffer.replace("")
|
|
else
|
|
if self.eof?
|
|
buffer.replace("")
|
|
return nil
|
|
end
|
|
buffer.replace(@string[@pos, length])
|
|
@pos += buffer.length
|
|
end
|
|
buffer.force_encoding('BINARY')
|
|
end
|
|
|
|
|
|
buffer
|
|
end
|
|
|
|
# strio.sysread(integer[, outbuf]) -> string
|
|
#
|
|
# Similar to #read, but raises +EOFError+ at end of string instead of
|
|
# returning +nil+, as well as IO#sysread does.
|
|
def sysread(length = nil, buffer = String.new)
|
|
val = read(length, buffer)
|
|
( buffer.clear && raise(IO::EOFError, "end of file reached")) if val == nil
|
|
val
|
|
end
|
|
alias_method :readpartial, :sysread
|
|
alias_method :read_nonblock, :sysread
|
|
|
|
# strio.readbyte -> fixnum
|
|
#
|
|
# See IO#readbyte.
|
|
#
|
|
def readbyte
|
|
raise(IO::EOFError, "end of file reached") if eof?
|
|
getbyte
|
|
end
|
|
|
|
# strio.seek(amount, whence=SEEK_SET) -> 0
|
|
#
|
|
# Seeks to a given offset _amount_ in the stream according to
|
|
# the value of _whence_ (see IO#seek).
|
|
#
|
|
def seek(offset, whence = ::IO::SEEK_SET)
|
|
raise(IOError, "closed stream") if closed?
|
|
raise TypeError unless offset.respond_to?(:to_int)
|
|
offset = offset.to_int
|
|
|
|
case whence
|
|
when ::IO::SEEK_CUR
|
|
# Seeks to offset plus current position
|
|
offset += @pos
|
|
when ::IO::SEEK_END
|
|
# Seeks to offet plus end of stream (usually offset is a negative value)
|
|
offset += @string.size
|
|
when ::IO::SEEK_SET, nil
|
|
# Seeks to the absolute location given by offset
|
|
else
|
|
raise Errno::EINVAL, "invalid whence"
|
|
end
|
|
|
|
raise Errno::EINVAL if (offset < 0)
|
|
@pos = offset
|
|
|
|
0
|
|
end
|
|
|
|
# strio.pos = integer -> integer
|
|
#
|
|
# Seeks to the given position (in bytes) in *strio*.
|
|
#
|
|
def pos=(pos)
|
|
raise Errno::EINVAL if pos < 0
|
|
@pos = pos
|
|
end
|
|
|
|
# strio.closed? -> true or false
|
|
#
|
|
# Returns +true+ if *strio* is completely closed, +false+ otherwise.
|
|
#
|
|
def closed?
|
|
!@readable && !@writable
|
|
end
|
|
|
|
# strio.close -> nil
|
|
#
|
|
# Closes strio. The *strio* is unavailable for any further data
|
|
# operations; an +IOError+ is raised if such an attempt is made.
|
|
#
|
|
def close
|
|
raise(IOError, "closed stream") if closed?
|
|
@readable = @writable = nil
|
|
end
|
|
|
|
# strio.closed_read? -> true or false
|
|
#
|
|
# Returns +true+ if *strio* is not readable, +false+ otherwise.
|
|
#
|
|
def closed_read?
|
|
!@readable
|
|
end
|
|
|
|
# strio.close_read -> nil
|
|
#
|
|
# Closes the read end of a StringIO. Will raise an +IOError+ if the
|
|
# *strio* is not readable.
|
|
#
|
|
def close_read
|
|
raise(IOError, "closing non-duplex IO for reading") unless @readable
|
|
@readable = nil
|
|
end
|
|
|
|
# strio.closed_write? -> true or false
|
|
#
|
|
# Returns +true+ if *strio* is not writable, +false+ otherwise.
|
|
#
|
|
def closed_write?
|
|
!@writable
|
|
end
|
|
|
|
# strio.eof -> true or false
|
|
# strio.eof? -> true or false
|
|
#
|
|
# Returns true if *strio* is at end of file. The stringio must be
|
|
# opened for reading or an +IOError+ will be raised.
|
|
#
|
|
def eof?
|
|
raise(IOError, "not opened for reading") unless @readable
|
|
@pos >= @string.length
|
|
end
|
|
alias_method :eof, :eof?
|
|
|
|
def binmode
|
|
self
|
|
end
|
|
|
|
def fcntl
|
|
raise NotImplementedError, "StringIO#fcntl is not implemented"
|
|
end
|
|
|
|
def flush
|
|
self
|
|
end
|
|
|
|
def fsync
|
|
0
|
|
end
|
|
|
|
# strio.pid -> nil
|
|
#
|
|
def pid
|
|
nil
|
|
end
|
|
|
|
# strio.sync -> true
|
|
#
|
|
# Returns +true+ always.
|
|
#
|
|
def sync
|
|
true
|
|
end
|
|
|
|
# strio.sync = boolean -> boolean
|
|
#
|
|
def sync=(value)
|
|
value
|
|
end
|
|
|
|
def tell
|
|
@pos
|
|
end
|
|
|
|
# strio.fileno -> nil
|
|
#
|
|
def fileno
|
|
nil
|
|
end
|
|
|
|
# strio.isatty -> nil
|
|
# strio.tty? -> nil
|
|
def isatty
|
|
false
|
|
end
|
|
alias_method :tty?, :isatty
|
|
|
|
def length
|
|
@string.length
|
|
end
|
|
alias_method :size, :length
|
|
|
|
# strio.getc -> string or nil
|
|
#
|
|
# Gets the next character from io.
|
|
# Returns nil if called at end of file
|
|
def getc
|
|
raise(IOError, "not opened for reading") unless @readable
|
|
return nil if eof?
|
|
result = @string[@pos]
|
|
@pos += 1
|
|
result
|
|
end
|
|
|
|
# strio.ungetc(string) -> nil
|
|
#
|
|
# Pushes back one character (passed as a parameter) onto *strio*
|
|
# such that a subsequent buffered read will return it. Pushing back
|
|
# behind the beginning of the buffer string is not possible. Nothing
|
|
# will be done if such an attempt is made.
|
|
# In other case, there is no limitation for multiple pushbacks.
|
|
#
|
|
def ungetc(chars)
|
|
raise(IOError, "not opened for reading") unless @readable
|
|
return nil if chars == nil
|
|
|
|
chars = chars.chr if chars.kind_of?(Fixnum)
|
|
raise TypeError unless chars.respond_to?(:to_str)
|
|
chars = chars.to_str
|
|
|
|
if @pos == 0
|
|
@string = chars + @string
|
|
elsif @pos > 0
|
|
@pos -= 1
|
|
@string[@pos] = chars
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
# strio.ungetbyte(fixnum) -> nil
|
|
#
|
|
# See IO#ungetbyte
|
|
#
|
|
def ungetbyte(bytes)
|
|
raise(IOError, "not opened for reading") unless @readable
|
|
return nil if bytes == nil
|
|
|
|
bytes = bytes.chr if bytes.kind_of?(Fixnum)
|
|
raise TypeError unless bytes.respond_to?(:to_str)
|
|
bytes = bytes.to_str
|
|
|
|
if @pos == 0
|
|
@string = bytes + @string
|
|
elsif @pos > 0
|
|
@pos -= 1
|
|
@string[@pos] = bytes
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
# strio.readchar -> fixnum
|
|
#
|
|
# See IO#readchar.
|
|
#
|
|
def readchar
|
|
raise(IO::EOFError, "end of file reached") if eof?
|
|
getc
|
|
end
|
|
|
|
# strio.each_char {|char| block } -> strio
|
|
#
|
|
# See IO#each_char.
|
|
#
|
|
def each_char
|
|
raise(IOError, "not opened for reading") unless @readable
|
|
if block_given?
|
|
@string.each_char{|c| yield(c)}
|
|
self
|
|
else
|
|
@string.each_char
|
|
end
|
|
end
|
|
alias_method :chars, :each_char
|
|
|
|
# strio.getbyte -> fixnum or nil
|
|
#
|
|
# See IO#getbyte.
|
|
def getbyte
|
|
raise(IOError, "not opened for reading") unless @readable
|
|
# Because we currently don't support bytes access
|
|
# the following code isn't used
|
|
# instead we are dealing with chars
|
|
result = @string.bytes.to_a[@pos]
|
|
@pos += 1 unless eof?
|
|
result
|
|
# getc
|
|
end
|
|
|
|
# strio.each_byte {|byte| block } -> strio
|
|
#
|
|
# See IO#each_byte.
|
|
#
|
|
def each_byte
|
|
raise(IOError, "not opened for reading") unless @readable
|
|
return self if (@pos > @string.length)
|
|
if block_given?
|
|
@string.each_byte{|b| @pos += 1; yield(b)}
|
|
self
|
|
else
|
|
@string.each_byte
|
|
end
|
|
end
|
|
alias_method :bytes, :each_byte
|
|
|
|
|
|
# strio.each(sep=$/) {|line| block } -> strio
|
|
# strio.each(limit) {|line| block } -> strio
|
|
# strio.each(sep, limit) {|line| block } -> strio
|
|
# strio.each_line(sep=$/) {|line| block } -> strio
|
|
# strio.each_line(limit) {|line| block } -> strio
|
|
# strio.each_line(sep,limit) {|line| block } -> strio
|
|
#
|
|
# See IO#each.
|
|
#
|
|
def each(sep=$/, limit=nil)
|
|
if block_given?
|
|
raise(IOError, "not opened for reading") unless @readable
|
|
sep, limit = getline_args(sep, limit)
|
|
if limit == 0
|
|
raise ArgumentError, "invalid limit: 0 for each and family"
|
|
end
|
|
while line = getline(sep, limit)
|
|
yield(line)
|
|
end
|
|
self
|
|
else
|
|
to_enum(:each, sep, limit)
|
|
end
|
|
end
|
|
alias_method :each_line, :each
|
|
alias_method :lines, :each
|
|
|
|
# strio.gets(sep=$/) -> string or nil
|
|
# strio.gets(limit) -> string or nil
|
|
# strio.gets(sep, limit) -> string or nil
|
|
#
|
|
# See IO#gets.
|
|
#
|
|
def gets(sep=$/, limit=nil)
|
|
sep, limit = getline_args(sep, limit)
|
|
$_ = getline(sep, limit)
|
|
end
|
|
|
|
# strio.readline(sep=$/) -> string
|
|
# strio.readline(limit) -> string or nil
|
|
# strio.readline(sep, limit) -> string or nil
|
|
#
|
|
# See IO#readline.
|
|
def readline(sep=$/, limit=nil)
|
|
raise(IO::EOFError, 'end of file reached') if eof?
|
|
sep, limit = getline_args(sep, limit)
|
|
$_ = getline(sep, limit)
|
|
end
|
|
|
|
# strio.readlines(sep=$/) -> array
|
|
# strio.readlines(limit) -> array
|
|
# strio.readlines(sep,limit) -> array
|
|
#
|
|
# See IO#readlines.
|
|
#
|
|
def readlines(sep=$/, limit=nil)
|
|
raise IOError, "not opened for reading" unless @readable
|
|
ary = []
|
|
sep, limit = getline_args(sep, limit)
|
|
if limit == 0
|
|
raise ArgumentError, "invalid limit: 0 for readlines"
|
|
end
|
|
while line = getline(sep, limit)
|
|
ary << line
|
|
end
|
|
ary
|
|
end
|
|
|
|
|
|
# strio.write(string) -> integer
|
|
# strio.syswrite(string) -> integer
|
|
#
|
|
# Appends the given string to the underlying buffer string of *strio*.
|
|
# The stream must be opened for writing. If the argument is not a
|
|
# string, it will be converted to a string using <code>to_s</code>.
|
|
# Returns the number of bytes written. See IO#write.
|
|
#
|
|
def write(str)
|
|
raise(IOError, "not opened for writing") unless @writable
|
|
raise(IOError, "not modifiable string") if @string.frozen?
|
|
|
|
str = str.to_s
|
|
return 0 if str.empty?
|
|
|
|
if @append || (@pos >= @string.length)
|
|
# add padding in case it's needed
|
|
str = str.rjust((@pos + str.length) - @string.length, "\000") if (@pos > @string.length)
|
|
enc1, enc2 = str.encoding, @string.encoding
|
|
if enc1 != enc2
|
|
str = str.dup.force_encoding(enc2)
|
|
end
|
|
@string << str
|
|
@pos = @string.length
|
|
else
|
|
@string[@pos, str.length] = str
|
|
@pos += str.length
|
|
@string.taint if str.tainted?
|
|
end
|
|
|
|
str.length
|
|
end
|
|
alias_method :syswrite, :write
|
|
alias_method :write_nonblock, :write
|
|
|
|
# strio << obj -> strio
|
|
#
|
|
# See IO#<<.
|
|
#
|
|
def <<(str)
|
|
self.write(str)
|
|
self
|
|
end
|
|
|
|
|
|
def close_write
|
|
raise(IOError, "closing non-duplex IO for writing") unless @writable
|
|
@writable = nil
|
|
end
|
|
|
|
# strio.truncate(integer) -> 0
|
|
#
|
|
# Truncates the buffer string to at most _integer_ bytes. The *strio*
|
|
# must be opened for writing.
|
|
#
|
|
def truncate(len)
|
|
raise(IOError, "closing non-duplex IO for writing") unless @writable
|
|
raise(TypeError) unless len.respond_to?(:to_int)
|
|
length = len.to_int
|
|
raise(Errno::EINVAL, "negative length") if (length < 0)
|
|
if length < @string.size
|
|
@string[length .. @string.size] = ""
|
|
else
|
|
@string = @string.ljust(length, "\000")
|
|
end
|
|
# send back what was passed, not our :to_int version
|
|
len
|
|
end
|
|
|
|
# strio.puts(obj, ...) -> nil
|
|
#
|
|
# Writes the given objects to <em>strio</em> as with
|
|
# <code>IO#print</code>. Writes a record separator (typically a
|
|
# newline) after any that do not already end with a newline sequence.
|
|
# If called with an array argument, writes each element on a new line.
|
|
# If called without arguments, outputs a single record separator.
|
|
#
|
|
# io.puts("this", "is", "a", "test")
|
|
#
|
|
# <em>produces:</em>
|
|
#
|
|
# this
|
|
# is
|
|
# a
|
|
# test
|
|
#
|
|
def puts(*args)
|
|
if args.empty?
|
|
write("\n")
|
|
else
|
|
args.each do |arg|
|
|
if arg == nil
|
|
line = "nil"
|
|
else
|
|
begin
|
|
arg = arg.to_ary
|
|
recur = false
|
|
arg.each do |a|
|
|
if arg == a
|
|
recur = true
|
|
break
|
|
else
|
|
puts a
|
|
end
|
|
end
|
|
next unless recur
|
|
line = '[...]'
|
|
rescue
|
|
line = arg.to_s
|
|
end
|
|
end
|
|
|
|
write(line)
|
|
write("\n") if line[-1] != ?\n
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
|
|
# strio.putc(obj) -> obj
|
|
#
|
|
# If <i>obj</i> is <code>Numeric</code>, write the character whose
|
|
# code is <i>obj</i>, otherwise write the first character of the
|
|
# string representation of <i>obj</i> to <em>strio</em>.
|
|
#
|
|
def putc(obj)
|
|
raise(IOError, "not opened for writing") unless @writable
|
|
|
|
if obj.is_a?(String)
|
|
char = obj[0]
|
|
else
|
|
raise TypeError unless obj.respond_to?(:to_int)
|
|
char = obj.to_int % 256
|
|
end
|
|
|
|
if @append || @pos == @string.length
|
|
@string << char
|
|
@pos = @string.length
|
|
elsif @pos > @string.length
|
|
@string = @string.ljust(@pos, "\000")
|
|
@string << char
|
|
@pos = @string.length
|
|
else
|
|
@string[@pos] = ("" << char)
|
|
@pos += 1
|
|
end
|
|
|
|
obj
|
|
end
|
|
|
|
|
|
# strio.print() => nil
|
|
# strio.print(obj, ...) => nil
|
|
#
|
|
# Writes the given object(s) to <em>strio</em>. The stream must be
|
|
# opened for writing. If the output record separator (<code>$\\</code>)
|
|
# is not <code>nil</code>, it will be appended to the output. If no
|
|
# arguments are given, prints <code>$_</code>. Objects that aren't
|
|
# strings will be converted by calling their <code>to_s</code> method.
|
|
# With no argument, prints the contents of the variable <code>$_</code>.
|
|
# Returns <code>nil</code>.
|
|
#
|
|
# io.print("This is ", 100, " percent.\n")
|
|
#
|
|
# <em>produces:</em>
|
|
#
|
|
# This is 100 percent.
|
|
#
|
|
def print(*args)
|
|
raise IOError, "not opened for writing" unless @writable
|
|
args << $_ if args.empty?
|
|
args.map! { |x| (x == nil) ? "nil" : x }
|
|
write((args << $\).flatten.join)
|
|
nil
|
|
end
|
|
|
|
# printf(strio, string [, obj ... ] ) => nil
|
|
#
|
|
# Equivalent to:
|
|
# strio.write(sprintf(string, obj, ...)
|
|
#
|
|
def printf(*args)
|
|
raise IOError, "not opened for writing" unless @writable
|
|
|
|
if args.size > 1
|
|
write(args.shift % args)
|
|
else
|
|
write(args.first)
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
def external_encoding
|
|
@string ? @string.encoding : nil
|
|
end
|
|
|
|
def internal_encoding
|
|
nil
|
|
end
|
|
|
|
def set_encoding(enc)
|
|
@string = @string.encode(enc)
|
|
self
|
|
end
|
|
|
|
protected
|
|
|
|
# meant to be overwritten by developers
|
|
def to_strio
|
|
self
|
|
end
|
|
|
|
def define_mode(mode=nil)
|
|
if mode == nil
|
|
# default modes
|
|
@string.frozen? ? set_mode_from_string("r") : set_mode_from_string("r+")
|
|
elsif mode.is_a?(Integer)
|
|
set_mode_from_integer(mode)
|
|
else
|
|
mode = mode.to_str
|
|
set_mode_from_string(mode)
|
|
end
|
|
end
|
|
|
|
def set_mode_from_string(mode)
|
|
@readable = @writable = @append = false
|
|
|
|
case mode
|
|
when "r", "rb"
|
|
@readable = true
|
|
when "r+", "rb+"
|
|
raise(Errno::EACCES) if @string.frozen?
|
|
@readable = true
|
|
@writable = true
|
|
when "w", "wb"
|
|
@string.frozen? ? raise(Errno::EACCES) : @string.replace("")
|
|
@writable = true
|
|
when "w+", "wb+"
|
|
@string.frozen? ? raise(Errno::EACCES) : @string.replace("")
|
|
@readable = true
|
|
@writable = true
|
|
when "a", "ab"
|
|
raise(Errno::EACCES) if @string.frozen?
|
|
@writable = true
|
|
@append = true
|
|
when "a+", "ab+"
|
|
raise(Errno::EACCES) if @string.frozen?
|
|
@readable = true
|
|
@writable = true
|
|
@append = true
|
|
end
|
|
end
|
|
|
|
def set_mode_from_integer(mode)
|
|
@readable = @writable = @append = false
|
|
|
|
case mode & (IO::RDONLY | IO::WRONLY | IO::RDWR)
|
|
when IO::RDONLY
|
|
@readable = true
|
|
@writable = false
|
|
when IO::WRONLY
|
|
@readable = false
|
|
@writable = true
|
|
raise(Errno::EACCES) if @string.frozen?
|
|
when IO::RDWR
|
|
@readable = true
|
|
@writable = true
|
|
raise(Errno::EACCES) if @string.frozen?
|
|
end
|
|
|
|
@append = true if (mode & IO::APPEND) != 0
|
|
raise(Errno::EACCES) if @append && @string.frozen?
|
|
@string.replace("") if (mode & IO::TRUNC) != 0
|
|
end
|
|
|
|
def getline(sep = $/, lim = nil)
|
|
raise(IOError, "not opened for reading") unless @readable
|
|
return nil if eof?
|
|
|
|
offset = limit = -1
|
|
if lim != nil
|
|
limit = lim - 1
|
|
offset = @pos + limit
|
|
end
|
|
|
|
if lim != nil && lim == 0
|
|
line = ""
|
|
elsif sep == nil
|
|
line = @string[@pos .. offset]
|
|
elsif sep.empty?
|
|
while @string[@pos] == ?\n
|
|
@pos += 1
|
|
limit -= 1
|
|
end
|
|
|
|
if stop = @string.index("\n\n", @pos)
|
|
stop += 1
|
|
line = @string[@pos .. stop]
|
|
if lim != nil && line[limit, 2] != "\n\n"
|
|
line = line[0 .. limit]
|
|
end
|
|
else
|
|
line = @string[@pos .. offset]
|
|
end
|
|
else
|
|
if stop = @string.index(sep, @pos)
|
|
line = @string[@pos .. (stop + sep.size - 1)]
|
|
else
|
|
line = @string[@pos .. offset]
|
|
end
|
|
end
|
|
@pos += line.size
|
|
@lineno += 1
|
|
|
|
line
|
|
end
|
|
|
|
def getline_args(sep = $/, lim = nil)
|
|
if lim == nil && !sep.kind_of?(String)
|
|
if !sep.respond_to?(:to_str)
|
|
lim = sep
|
|
sep = nil
|
|
end
|
|
end
|
|
|
|
if lim != nil
|
|
raise TypeError unless lim.respond_to?(:to_int)
|
|
lim = lim.to_int
|
|
end
|
|
sep = sep.to_str unless (sep == nil)
|
|
|
|
return sep, lim
|
|
end
|
|
|
|
end
|