5 ivar_as_index :__ivars__ => 0, :descriptor => 1, :buffer => 2, :mode => 3
10 ivar_as_index :bytes => 0, :characters => 1, :encoding => 2, :data => 3, :hash => 4, :shared => 5
13 # Create a buffer of +size+ bytes. The buffer contains an internal Channel
14 # object it uses to fill itself.
16 @data = ByteArray.new(size)
22 @channel = Channel.new
26 # Block until the buffer receives more data
34 # Indicates how many bytes are left
40 # Remove +count+ bytes from the front of the buffer and return them.
41 # All other bytes are moved up.
42 def shift_front(count)
43 count = @bytes if count > @bytes
45 str = String.buffer count
46 str.copy_from self, 0, count, 0
49 @data.move_bytes count, rest, 0
56 # Empty the contents of the Buffer into a String object and return it.
58 str = String.buffer @bytes
59 str.copy_from self, 0, @bytes, 0
69 # Indicates if the Buffer has no more room.
81 # Fill the buffer from IO object +io+. The buffer requests +unused+
82 # bytes, but may not receive that many. Any new data causes this to
85 Scheduler.send_on_readable @channel, io, self, unused()
86 obj = @channel.receive
88 raise IOError, "error occured while filling buffer (#{obj})"
97 "#<IO::Buffer:0x%x total=%p bytes=%p characters=%p data=%p>" % [
98 object_id, @total, @bytes, @characters, @data
103 # Match the buffer against Regexp +reg+, and remove bytes starting
104 # at the beginning of the buffer, up to the end of where the Regexp
107 if m = reg.match(self)
109 return shift_front(idx)
117 F_GETFL = Rubinius::RUBY_CONFIG['rbx.platform.fcntl.F_GETFL']
118 F_SETFL = Rubinius::RUBY_CONFIG['rbx.platform.fcntl.F_SETFL']
119 ACCMODE = Rubinius::RUBY_CONFIG['rbx.platform.fcntl.O_ACCMODE']
121 SEEK_SET = Rubinius::RUBY_CONFIG['rbx.platform.io.SEEK_SET']
122 SEEK_CUR = Rubinius::RUBY_CONFIG['rbx.platform.io.SEEK_CUR']
123 SEEK_END = Rubinius::RUBY_CONFIG['rbx.platform.io.SEEK_END']
125 RDONLY = Rubinius::RUBY_CONFIG['rbx.platform.file.O_RDONLY']
126 WRONLY = Rubinius::RUBY_CONFIG['rbx.platform.file.O_WRONLY']
127 RDWR = Rubinius::RUBY_CONFIG['rbx.platform.file.O_RDWR']
129 CREAT = Rubinius::RUBY_CONFIG['rbx.platform.file.O_CREAT']
130 EXCL = Rubinius::RUBY_CONFIG['rbx.platform.file.O_EXCL']
131 NOCTTY = Rubinius::RUBY_CONFIG['rbx.platform.file.O_NOCTTY']
132 TRUNC = Rubinius::RUBY_CONFIG['rbx.platform.file.O_TRUNC']
133 APPEND = Rubinius::RUBY_CONFIG['rbx.platform.file.O_APPEND']
134 NONBLOCK = Rubinius::RUBY_CONFIG['rbx.platform.file.O_NONBLOCK']
135 SYNC = Rubinius::RUBY_CONFIG['rbx.platform.file.O_SYNC']
137 # TODO: these flags should probably be imported from Platform
147 def self.for_fd(fd = -1, mode = nil)
151 def self.foreach(name, sep_string = $/, &block)
153 io = File.open(StringValue(name), 'r')
154 sep = StringValue(sep_string)
156 while(line = io.gets(sep))
165 # Creates a new IO object to access the existing stream referenced by the
166 # descriptor given. The stream is not copied in any way so anything done on
167 # one IO will affect any other IOs accessing the same descriptor.
169 # The mode string given must be compatible with the original one so going
170 # 'r' from 'w' cannot be done but it is possible to go from 'w+' to 'r', for
171 # example (since the stream is not being "widened".)
173 # The initialization will verify that the descriptor given is a valid one.
174 # Errno::EBADF will be raised if that is not the case. If the mode is
175 # incompatible, it will raise Errno::EINVAL instead.
179 return io unless block_given?
184 io.close rescue nil unless io.closed?
188 def self.parse_mode(mode)
195 ret |= WRONLY | CREAT | TRUNC
197 ret |= WRONLY | CREAT | APPEND
199 raise ArgumentError, "invalid mode -- #{mode}"
202 return ret if mode.length == 1
206 ret &= ~(RDONLY | WRONLY)
211 raise ArgumentError, "invalid mode -- #{mode}"
214 return ret if mode.length == 2
218 ret &= ~(RDONLY | WRONLY)
223 raise ArgumentError, "invalid mode -- #{mode}"
230 # Creates a pair of pipe endpoints (connected to each other)
231 # and returns them as a two-element array of IO objects:
232 # [ read_file, write_file ]. Not available on all platforms.
234 # In the example below, the two processes close the ends of
235 # the pipe that they are not using. This is not just a cosmetic
236 # nicety. The read end of a pipe will not generate an end of
237 # file condition if there are any writers with the pipe still
238 # open. In the case of the parent process, the rd.read will
239 # never return if it does not first issue a wr.close.
245 # puts "Parent got: <#{rd.read}>"
250 # puts "Sending message to parent"
256 # Sending message to parent
257 # Parent got: <Hi Dad>
261 out = create_pipe(lhs, rhs)
268 # Runs the specified command string as a subprocess;
269 # the subprocess‘s standard input and output will be
270 # connected to the returned IO object. If cmd_string
271 # starts with a ``-’’, then a new instance of Ruby is
272 # started as the subprocess. The default mode for the
273 # new file object is ``r’’, but mode may be set to any
274 # of the modes listed in the description for class IO.
276 # If a block is given, Ruby will run the command as a
277 # child connected to Ruby with a pipe. Ruby‘s end of
278 # the pipe will be passed as a parameter to the block.
279 # At the end of block, Ruby close the pipe and sets $?.
280 # In this case IO::popen returns the value of the block.
282 # If a block is given with a cmd_string of ``-’’, the
283 # block will be run in two separate processes: once in
284 # the parent, and once in a child. The parent process
285 # will be passed the pipe object as a parameter to the
286 # block, the child version of the block will be passed
287 # nil, and the child‘s standard in and standard out will
288 # be connected to the parent through the pipe.
289 # Not available on all platforms.
291 # f = IO.popen("uname")
293 # puts "Parent is #{Process.pid}"
294 # IO.popen ("date") { |f| puts f.gets }
295 # IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f}"}
301 # Wed Apr 9 08:53:52 CDT 2003
302 # 26169 is here, f is
303 # 26166 is here, f is #<IO:0x401b3d44>
304 # #<Process::Status: pid=26166,exited(0)>
305 def self.popen(str, mode = "r")
306 if str == "+-+" and !block_given?
307 raise ArgumentError, "this mode requires a block currently"
310 mode = parse_mode mode
315 if mode & IO::RDWR != 0 then
318 elsif mode & IO::WRONLY != 0 then
324 pa_read, ch_write = IO.pipe if readable
325 ch_read, pa_write = IO.pipe if writable
327 pid = Process.fork do
330 STDOUT.reopen ch_write
341 Process.replace "/bin/sh", ["sh", "-c", str]
345 ch_write.close if readable
346 ch_read.close if writable
348 # See bottom for definition
349 pipe = IO::BidirectionalPipe.new pid, pa_read, pa_write
363 # Opens the file, optionally seeks to the given offset,
364 # then returns length bytes (defaulting to the rest of
365 # the file). read ensures the file is closed before returning.
367 # IO.read("testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
368 # IO.read("testfile", 20) #=> "This is line one\nThi"
369 # IO.read("testfile", 20, 10) #=> "ne one\nThis is line "
370 def self.read(name, length = Undefined, offset = 0)
371 name = StringValue(name)
375 offset = Type.coerce_to(offset, Fixnum, :to_int)
378 raise Errno::EINVAL, "offset must not be negative"
381 unless length.equal?(Undefined)
382 length = Type.coerce_to(length, Fixnum, :to_int)
385 raise ArgumentError, "length must not be negative"
389 File.open(name) do |f|
390 f.seek(offset) unless offset.zero?
392 if length.equal?(Undefined)
401 # Reads the entire file specified by name as individual
402 # lines, and returns those lines in an array. Lines are
403 # separated by sep_string.
405 # a = IO.readlines("testfile")
406 # a[0] #=> "This is line one\n"
407 def self.readlines(name, sep_string = $/)
408 io = File.open(StringValue(name), 'r')
412 io.readlines(sep_string)
419 # Select() examines the I/O descriptor sets who are passed in
420 # +read_array+, +write_array+, and +error_array+ to see if some of their descriptors are
421 # ready for reading, are ready for writing, or have an exceptions pending.
423 # If +timeout+ is not nil, it specifies a maximum interval to wait
424 # for the selection to complete. If timeout is nil, the select
425 # blocks indefinitely.
427 # +write_array+, +error_array+, and +timeout+ may be left as nil if they are
429 def self.select(read_array, write_array = nil, error_array = nil,
434 read_array.each do |readable|
435 Scheduler.send_on_readable chan, readable, nil, nil
439 raise NotImplementedError, "write_array is not supported" if write_array
440 raise NotImplementedError, "error_array is not supported" if error_array
442 # HACK can't do this yet
444 # write_array.each do |writable|
445 # Scheduler.send_on_writable chan, writable, nil, nil
450 # error_array.each do |errorable|
451 # Scheduler.send_on_error chan, errorable, nil, nil
455 Scheduler.send_in_microseconds chan, (timeout * 1_000_000).to_i, nil if timeout
459 return nil if value == 1 # timeout
461 io = read_array.find { |readable| readable.fileno == value }
463 return nil if io.nil?
469 # Opens the given path, returning the underlying file descriptor as a Fixnum.
470 # IO.sysopen("testfile") #=> 3
471 def self.sysopen(path, mode = "r", perm = 0666)
472 if mode.kind_of?(String)
473 mode = parse_mode(mode)
476 return open_with_mode(path, mode, perm)
479 def initialize(fd, mode = nil)
480 fd = Type.coerce_to fd, Integer, :to_int
482 # Descriptor must be an open and valid one
483 raise Errno::EBADF, "Invalid descriptor #{fd}" if fd < 0
485 cur_mode = Platform::POSIX.fcntl(fd, F_GETFL, 0)
486 raise Errno::EBADF, "Invalid descriptor #{fd}" if cur_mode < 0
489 # Must support the desired mode.
490 # O_ACCMODE is /undocumented/ for fcntl() on some platforms
491 # but it should work. If there is a problem, check it though.
492 new_mode = IO.parse_mode(mode) & ACCMODE
493 cur_mode = cur_mode & ACCMODE
495 if cur_mode != RDWR and cur_mode != new_mode
496 raise Errno::EINVAL, "Invalid mode '#{mode}' for existing descriptor #{fd}"
504 # Obtains a new duplicate descriptor for the current one.
505 def initialize_copy(original) # :nodoc:
506 @descriptor = Platform::POSIX.dup(@descriptor)
509 private :initialize_copy
511 def setup(desc = nil, mode = nil)
512 @descriptor = desc if desc
514 @buffer = IO::Buffer.new(BufferSize)
524 def __ivars__ ; @__ivars__ ; end
527 # Puts ios into binary mode. This is useful only in
528 # MS-DOS/Windows environments. Once a stream is in
529 # binary mode, it cannot be reset to nonbinary mode.
534 def breadall(buffer=nil)
535 return "" if @eof and @buffer.empty?
542 bytes = buf.fill_from(self)
544 if !bytes or buf.full?
553 buffer = StringValue buffer
554 buffer.replace output
563 # Closes the read end of a duplex I/O stream (i.e., one
564 # that contains both a read and a write stream, such as
565 # a pipe). Will raise an IOError if the stream is not duplexed.
567 # f = IO.popen("/bin/sh","r+")
572 # prog.rb:3:in `readlines': not opened for reading (IOError)
575 # TODO raise IOError if writable
580 # Closes the write end of a duplex I/O stream (i.e., one
581 # that contains both a read and a write stream, such as
582 # a pipe). Will raise an IOError if the stream is not duplexed.
584 # f = IO.popen("/bin/sh","r+")
589 # prog.rb:3:in `write': not opened for writing (IOError)
590 # from prog.rb:3:in `print'
593 # TODO raise IOError if readable
598 # Returns true if ios is completely closed (for duplex
599 # streams, both reader and writer), false otherwise.
601 # f = File.new("testfile")
604 # f = IO.popen("/bin/sh","r+")
605 # f.close_write #=> nil
606 # f.closed? #=> false
607 # f.close_read #=> nil
618 raise IOError, "closed stream" if closed?
623 # Executes the block for every line in ios, where
624 # lines are separated by sep_string. ios must be
625 # opened for reading or an IOError will be raised.
627 # f = File.new("testfile")
628 # f.each {|line| puts "#{f.lineno}: #{line}" }
631 # 1: This is line one
632 # 2: This is line two
633 # 3: This is line three
636 while line = gets_helper(sep)
641 alias_method :each_line, :each
644 yield getc until eof?
650 # Set the pipe so it is at the end of the file
656 # Returns true if ios is at end of file that means
657 # there are no more data to read. The stream must be
658 # opened for reading or an IOError will be raised.
660 # f = File.new("testfile")
661 # dummy = f.readlines
663 # If ios is a stream such as pipe or socket, IO#eof?
664 # blocks until the other end sends some data or closes it.
667 # Thread.new { sleep 1; w.close }
668 # r.eof? #=> true after 1 second blocking
671 # Thread.new { sleep 1; w.puts "a" }
672 # r.eof? #=> false after 1 second blocking
675 # r.eof? # blocks forever
676 # Note that IO#eof? reads data to a input buffer. So IO#sysread doesn‘t work with IO#eof?.
678 read 0 # HACK force check
679 @eof and @buffer.empty?
682 alias_method :eof, :eof?
685 # Provides a mechanism for issuing low-level commands to
686 # control or query file-oriented I/O streams. Arguments
687 # and results are platform dependent. If arg is a number,
688 # its value is passed directly. If it is a string, it is
689 # interpreted as a binary sequence of bytes (Array#pack
690 # might be a useful way to build this string). On Unix
691 # platforms, see fcntl(2) for details. Not implemented on all platforms.
692 def fcntl(command, arg=0)
693 raise IOError, "closed stream" if closed?
694 if arg.kind_of? Fixnum then
695 Platform::POSIX.fcntl(descriptor, command, arg)
697 raise NotImplementedError, "cannot handle #{arg.class}"
702 # Returns an integer representing the numeric file descriptor for ios.
704 # $stdin.fileno #=> 0
705 # $stdout.fileno #=> 1
707 raise IOError, "closed stream" if closed?
711 alias_method :to_i, :fileno
714 # Flushes any buffered data within ios to the underlying
715 # operating system (note that this is Ruby internal
716 # buffering only; the OS may buffer the data as well).
718 # $stdout.print "no newline"
724 raise IOError, "closed stream" if closed?
729 # Immediately writes all buffered data in ios to disk. Returns
730 # nil if the underlying operating system does not support fsync(2).
731 # Note that fsync differs from using IO#sync=. The latter ensures
732 # that data is flushed from Ruby‘s buffers, but doesn‘t not guarantee
733 # that the underlying operating system actually writes it to disk.
735 raise IOError, 'closed stream' if closed?
737 err = Platform::POSIX.fsync @descriptor
739 Errno.handle 'fsync(2)' if err < 0
745 # Gets the next 8-bit byte (0..255) from ios.
746 # Returns nil if called at end of file.
748 # f = File.new("testfile")
753 return nil if char.nil?
758 # Reads the next ``line’’ from the I/O stream;
759 # lines are separated by sep_string. A separator
760 # of nil reads the entire contents, and a zero-length
761 # separator reads the input a paragraph at a time (two
762 # successive newlines in the input separate paragraphs).
763 # The stream must be opened for reading or an IOError
764 # will be raised. The line read in will be returned and
765 # also assigned to $_. Returns nil if called at end of file.
767 # File.new("testfile").gets #=> "This is line one\n"
768 # $_ #=> "This is line one\n"
772 line = gets_helper sep
773 line.taint unless line.nil?
783 # Several methods use similar rules for reading strings from IO, but differ
784 # slightly. This helper is an extraction of the code.
786 def gets_helper(sep=$/)
787 raise IOError, "closed stream" if closed?
788 return nil if @eof and @buffer.empty?
790 return breadall() unless sep
795 return gets_stripped($/ + $/)
800 if str = buf.clip_to(reg)
804 # Do an initial fill.
805 return nil if !buf.fill_from(self) and buf.empty?
809 if str = buf.clip_to(reg)
817 if !buf.fill_from(self)
826 return output << buf.as_str
846 def gets_stripped(sep)
849 if m = /^\n+/m.match(buf)
850 buf.shift_front(m.end(0)) if m.begin(0) == 0
853 str = gets_helper(sep)
855 if m = /^\n+/m.match(buf)
856 buf.shift_front(m.end(0)) if m.begin(0) == 0
863 # Return a string describing this IO object.
865 "#<#{self.class}:0x#{object_id.to_s(16)}>"
869 # Returns the current line number in ios. The
870 # stream must be opened for reading. lineno
871 # counts the number of times gets is called,
872 # rather than the number of newlines encountered.
873 # The two values will differ if gets is called with
874 # a separator other than newline. See also the $. variable.
876 # f = File.new("testfile")
878 # f.gets #=> "This is line one\n"
880 # f.gets #=> "This is line two\n"
883 raise IOError, 'closed stream' if closed?
889 # Manually sets the current line number to the
890 # given value. $. is updated only on the next read.
892 # f = File.new("testfile")
893 # f.gets #=> "This is line one\n"
897 # $. # lineno of last read #=> 1
898 # f.gets #=> "This is line two\n"
899 # $. # lineno of last read #=> 1001
900 def lineno=(line_number)
901 raise IOError, 'closed stream' if closed?
903 raise TypeError if line_number.nil?
905 @lineno = Integer line_number
910 # Returns the process ID of a child process
911 # associated with ios. This will be set by IO::popen.
913 # pipe = IO.popen("-")
915 # $stderr.puts "In parent, child pid is #{pipe.pid}"
917 # $stderr.puts "In child, pid is #{$$}"
921 # In child, pid is 26209
922 # In parent, child pid is 26209
933 alias_method :tell, :pos
936 # Seeks to the given position (in bytes) in ios.
938 # f = File.new("testfile")
940 # f.gets #=> "This is line two\n"
942 offset = Integer offset
944 seek offset, SEEK_SET
948 # Writes each given argument.to_s to the stream or $_ (the result of last
949 # IO#gets) if called without arguments. Appends $\.to_s to output. Returns
955 args.each {|o| write o.to_s }
963 # Formats and writes to ios, converting parameters under
964 # control of the format string. See Kernel#sprintf for details.
965 def printf(fmt, *args)
966 write Sprintf.new(fmt, *args).parse
970 # If obj is Numeric, write the character whose code is obj,
971 # otherwise write the first character of the string
972 # representation of obj to ios.
980 byte = if obj.__kind_of__ String then
983 Type.coerce_to(obj, Integer, :to_int) & 0xff
990 # Writes the given objects to ios as with IO#print.
991 # Writes a record separator (typically a newline)
992 # after any that do not already end with a newline
993 # sequence. If called with an array argument, writes
994 # each element on a new line. If called without arguments,
995 # outputs a single record separator.
997 # $stdout.puts("this", "is", "a", "test")
1006 write DEFAULT_RECORD_SEPARATOR
1011 elsif RecursionGuard.inspecting?(arg)
1013 elsif arg.kind_of?(Array)
1014 RecursionGuard.inspect(arg) do
1025 write DEFAULT_RECORD_SEPARATOR unless str.suffix?(DEFAULT_RECORD_SEPARATOR)
1034 # Reads at most length bytes from the I/O stream,
1035 # or to the end of file if length is omitted or is
1036 # nil. length must be a non-negative integer or nil.
1037 # If the optional buffer argument is present, it must
1038 # reference a String, which will receive the data.
1040 # At end of file, it returns nil or "" depend on length.
1041 # ios.read() and ios.read(nil) returns "". ios.read(positive-integer) returns nil.
1043 # f = File.new("testfile")
1044 # f.read(16) #=> "This is line one"
1045 def read(size=nil, buffer=nil)
1046 raise IOError, "closed stream" if closed?
1047 return breadall(buffer) unless size
1049 return nil if @eof and @buffer.empty?
1058 if needed > 0 and buf.size >= needed
1059 output << buf.shift_front(needed)
1062 bytes = buf.fill_from(self)
1065 done = needed - bytes <= 0
1070 if done or buf.full?
1071 output << buf.shift_front(needed)
1072 needed = size - output.length
1075 break if done or needed == 0
1080 buffer = StringValue buffer
1081 buffer.replace output
1090 # Reads at most maxlen bytes from ios using read(2) system
1091 # call after O_NONBLOCK is set for the underlying file descriptor.
1093 # If the optional outbuf argument is present, it must reference
1094 # a String, which will receive the data.
1096 # read_nonblock just calls read(2). It causes all errors read(2)
1097 # causes: EAGAIN, EINTR, etc. The caller should care such errors.
1099 # read_nonblock causes EOFError on EOF.
1101 # If the read buffer is not empty, read_nonblock reads from the
1102 # buffer like readpartial. In this case, read(2) is not called.
1103 def read_nonblock(size, buffer = nil)
1104 raise IOError, "closed stream" if closed?
1105 prim_read(size, buffer)
1109 # Reads a character as with IO#getc, but raises an EOFError on end of file.
1113 raise EOFError, 'end of file reached' if char.nil?
1119 # Reads a line as with IO#gets, but raises an EOFError on end of file.
1120 def readline(sep=$/)
1122 raise EOFError, "end of file" unless out
1127 # Reads all of the lines in ios, and returns them in an array.
1128 # Lines are separated by the optional sep_string. If sep_string
1129 # is nil, the rest of the stream is returned as a single record.
1130 # The stream must be opened for reading or an IOError will be raised.
1132 # f = File.new("testfile")
1133 # f.readlines[0] #=> "This is line one\n"
1134 def readlines(sep=$/)
1136 while line = gets(sep)
1143 # Reads at most maxlen bytes from the I/O stream. It blocks
1144 # only if ios has no data immediately available. It doesn‘t
1145 # block if some data available. If the optional outbuf argument
1146 # is present, it must reference a String, which will receive the
1147 # data. It raises EOFError on end of file.
1149 # readpartial is designed for streams such as pipe, socket, tty,
1150 # etc. It blocks only when no data immediately available. This
1151 # means that it blocks only when following all conditions hold.
1153 # the buffer in the IO object is empty.
1154 # the content of the stream is empty.
1155 # the stream is not reached to EOF.
1156 # When readpartial blocks, it waits data or EOF on the stream.
1157 # If some data is reached, readpartial returns with the data.
1158 # If EOF is reached, readpartial raises EOFError.
1160 # When readpartial doesn‘t blocks, it returns or raises immediately.
1161 # If the buffer is not empty, it returns the data in the buffer.
1162 # Otherwise if the stream has some content, it returns the data in
1163 # the stream. Otherwise if the stream is reached to EOF, it raises EOFError.
1165 # r, w = IO.pipe # buffer pipe content
1166 # w << "abc" # "" "abc".
1167 # r.readpartial(4096) #=> "abc" "" ""
1168 # r.readpartial(4096) # blocks because buffer and pipe is empty.
1170 # r, w = IO.pipe # buffer pipe content
1171 # w << "abc" # "" "abc"
1172 # w.close # "" "abc" EOF
1173 # r.readpartial(4096) #=> "abc" "" EOF
1174 # r.readpartial(4096) # raises EOFError
1176 # r, w = IO.pipe # buffer pipe content
1177 # w << "abc\ndef\n" # "" "abc\ndef\n"
1178 # r.gets #=> "abc\n" "def\n" ""
1179 # w << "ghi\n" # "def\n" "ghi\n"
1180 # r.readpartial(4096) #=> "def\n" "" "ghi\n"
1181 # r.readpartial(4096) #=> "ghi\n" "" ""
1182 # Note that readpartial behaves similar to sysread. The differences are:
1184 # If the buffer is not empty, read from the buffer instead
1185 # of "sysread for buffered IO (IOError)".
1186 # It doesn‘t cause Errno::EAGAIN and Errno::EINTR. When readpartial
1187 # meets EAGAIN and EINTR by read system call, readpartial retry the system call.
1188 # The later means that readpartial is nonblocking-flag insensitive. It
1189 # blocks on the situation IO#sysread causes Errno::EAGAIN as if the fd is blocking mode.
1190 def readpartial(size, buffer = nil)
1191 raise ArgumentError, 'negative string size' unless size >= 0
1192 raise IOError, "closed stream" if closed?
1194 buffer = '' if buffer.nil?
1196 in_buf = @buffer.shift_front size
1197 size = size - in_buf.length
1199 in_buf << sysread(size) if size > 0
1201 buffer.replace in_buf
1206 alias_method :orig_reopen, :reopen
1209 # Reassociates ios with the I/O stream given in other_IO or to
1210 # a new stream opened on path. This may dynamically change the
1211 # actual class of this stream.
1213 # f1 = File.new("testfile")
1214 # f2 = File.new("testfile")
1215 # f2.readlines[0] #=> "This is line one\n"
1216 # f2.reopen(f1) #=> #<File:testfile>
1217 # f2.readlines[0] #=> "This is line one\n"
1218 def reopen(other, mode = 'r')
1219 other = if other.respond_to? :to_io then
1222 File.new other, mode
1225 raise IOError, 'closed stream' if other.closed?
1233 # Positions ios to the beginning of input, resetting lineno to zero.
1235 # f = File.new("testfile")
1236 # f.readline #=> "This is line one\n"
1239 # f.readline #=> "This is line one\n"
1248 # Seeks to a given offset +amount+ in the stream according to the value of whence:
1250 # IO::SEEK_CUR | Seeks to _amount_ plus current position
1251 # --------------+----------------------------------------------------
1252 # IO::SEEK_END | Seeks to _amount_ plus end of stream (you probably
1253 # | want a negative value for _amount_)
1254 # --------------+----------------------------------------------------
1255 # IO::SEEK_SET | Seeks to the absolute location given by _amount_
1258 # f = File.new("testfile")
1259 # f.seek(-13, IO::SEEK_END) #=> 0
1260 # f.readline #=> "And so on...\n"
1261 def seek(amount, whence=SEEK_SET)
1262 raise IOError, "closed stream" if closed?
1263 # Unseek the still buffered amount
1264 unless @buffer.empty?
1265 prim_seek(-@buffer.size, SEEK_CUR)
1270 prim_seek amount, whence
1274 # Returns status information for ios as an object of type File::Stat.
1276 # f = File.new("testfile")
1278 # "%o" % s.mode #=> "100644"
1279 # s.blksize #=> 4096
1280 # s.atime #=> Wed Apr 09 08:53:54 CDT 2003
1282 raise IOError, "closed stream" if closed?
1284 File::Stat.from_fd fileno
1288 # Returns the current ``sync mode’’ of ios. When sync mode is true,
1289 # all output is immediately flushed to the underlying operating
1290 # system and is not buffered by Ruby internally. See also IO#fsync.
1292 # f = File.new("testfile")
1295 raise IOError, "closed stream" if closed?
1301 # The current implementation does no write buffering, so we're always in
1305 raise IOError, "closed stream" if closed?
1309 # Reads integer bytes from ios using a low-level read and returns
1310 # them as a string. Do not mix with other methods that read from
1311 # ios or you may get unpredictable results. Raises SystemCallError
1312 # on error and EOFError at end of file.
1314 # f = File.new("testfile")
1315 # f.sysread(16) #=> "This is line one"
1316 def sysread(size, buffer = nil)
1317 raise ArgumentError, 'negative string size' unless size >= 0
1318 raise IOError, "closed stream" if closed?
1320 buffer = "\0" * size unless buffer
1323 Scheduler.send_on_readable chan, self, buffer, size
1324 raise EOFError if chan.receive.nil?
1330 # Seeks to a given offset in the stream according to the value
1331 # of whence (see IO#seek for values of whence). Returns the new offset into the file.
1333 # f = File.new("testfile")
1334 # f.sysseek(-13, IO::SEEK_END) #=> 53
1335 # f.sysread(10) #=> "And so on."
1336 def sysseek(amount, whence=SEEK_SET)
1337 raise IOError, "closed stream" if closed?
1338 Platform::POSIX.lseek(@descriptor, amount, whence)
1345 alias_method :prim_tty?, :tty?
1348 # Returns true if ios is associated with a terminal device (tty), false otherwise.
1350 # File.new("testfile").isatty #=> false
1351 # File.new("/dev/tty").isatty #=> true
1353 raise IOError, "closed stream" if closed?
1357 alias_method :isatty, :tty?
1359 def wait_til_readable
1361 Scheduler.send_on_readable chan, self, nil, nil
1365 alias_method :prim_write, :write
1368 # Pushes back one character (passed as a parameter) onto ios,
1369 # such that a subsequent buffered read will return it. Only one
1370 # character may be pushed back before a subsequent read operation
1371 # (that is, you will be able to read only the last of several
1372 # characters that have been pushed back). Has no effect with
1373 # unbuffered reads (such as IO#sysread).
1375 # f = File.new("testfile") #=> #<File:testfile>
1377 # f.ungetc(c) #=> nil
1380 raise IOError, "closed stream" if closed?
1381 # If we have buffered data, rewind.
1382 unless @buffer.empty?
1388 return 0 if data.length == 0
1389 raise IOError if ((Platform::POSIX.fcntl(@descriptor, F_GETFL, 0) & ACCMODE) == RDONLY)
1393 alias_method :syswrite, :write
1394 alias_method :write_nonblock, :write
1396 def self.after_loaded()
1397 remove_method :orig_reopen
1398 # Nothing to do right now
1404 # Implements the pipe returned by IO::pipe.
1406 class IO::BidirectionalPipe < IO
1433 def initialize(pid, read, write)
1440 raise IOError, 'not opened for reading' if @read.nil?
1444 raise IOError, 'not opened for writing' if @write.nil?
1448 # Closes ios and flushes any pending writes to the
1449 # operating system. The stream is unavailable for
1450 # any further data operations; an IOError is raised
1451 # if such an attempt is made. I/O streams are
1452 # automatically closed when they are claimed by
1453 # the garbage collector.
1455 # If ios is opened by IO.popen, close sets $?.
1457 @read.close if @read and not @read.closed?
1458 @write.close if @write and not @write.closed?
1470 if @read and @write then
1471 @read.closed? and @write.closed?
1480 raise IOError, 'closed stream' if @read.closed?
1482 @read.close if @read
1486 raise IOError, 'closed stream' if @write.closed?
1488 @write.close if @write
1491 def method_missing(message, *args, &block)
1492 if READ_METHODS.include? message then
1495 @read.send(message, *args, &block)
1496 elsif WRITE_METHODS.include? message then
1499 @write.send(message, *args, &block)
1506 raise IOError, 'closed stream' if closed?
1511 def self.after_loaded
1512 (READ_METHODS + WRITE_METHODS).each do |method|