#include <errno.h>
`}
-# File Abstract Stream
-abstract class FStream
- super IOS
+# `Stream` used to interact with a File or FileDescriptor
+abstract class FileStream
+ super Stream
# The path of the file.
var path: nullable String = null
# File descriptor of this file
fun fd: Int do return _file.fileno
- # Sets the buffering mode for the current FStream
+ # Sets the buffering mode for the current FileStream
#
# If the buf_size is <= 0, its value will be 512 by default
#
fun set_buffering_mode(buf_size, mode: Int) do
if buf_size <= 0 then buf_size = 512
if _file.set_buffering_type(buf_size, mode) != 0 then
- last_error = new IOError("Error while changing buffering type for FStream, returned error {sys.errno.strerror}")
+ last_error = new IOError("Error while changing buffering type for FileStream, returned error {sys.errno.strerror}")
end
end
end
-# File input stream
-class IFStream
- super FStream
- super BufferedIStream
- super PollableIStream
+# `Stream` that can read from a File
+class FileReader
+ super FileStream
+ super BufferedReader
+ super PollableReader
# Misc
# Open the same file again.
redef fun close
do
- if _file.address_is_null then return
+ if _file == null or _file.address_is_null then return
var i = _file.io_close
_buffer.clear
end_reached = true
+ _file = null
end
redef fun fill_buffer
end
end
-# File output stream
-class OFStream
- super FStream
- super OStream
+# `Stream` that can write to a File
+class FileWriter
+ super FileStream
+ super Writer
redef fun write(s)
do
redef fun close
do
+ if _file == null then return
if _file.address_is_null then
if last_error != null then return
last_error = new IOError("Cannot close unopened write stream")
last_error = new IOError("Close failed due to error {sys.errno.strerror}")
end
_is_writable = false
+ _file = null
end
redef var is_writable = false
# Standard input stream.
class Stdin
- super IFStream
+ super FileReader
init do
_file = new NativeFile.native_stdin
# Standard output stream.
class Stdout
- super OFStream
+ super FileWriter
init do
_file = new NativeFile.native_stdout
path = "/dev/stdout"
_is_writable = true
+ set_buffering_mode(256, sys.buffer_mode_line)
end
end
# Standard error stream.
class Stderr
- super OFStream
+ super FileWriter
init do
_file = new NativeFile.native_stderr
path = "/dev/stderr"
###############################################################################
-redef class Streamable
+redef class Writable
# Like `write_to` but take care of creating the file
fun write_to_file(filepath: String)
do
- var stream = new OFStream.open(filepath)
+ var stream = new FileWriter.open(filepath)
write_to(stream)
stream.close
end
# Open this file for reading
#
# Require: `exists and not link_stat.is_dir`
- fun open_ro: IFStream
+ fun open_ro: FileReader
do
# TODO manage streams error when they are merged
- return new IFStream.open(path)
+ return new FileReader.open(path)
end
# Open this file for writing
#
# Require: `not exists or not stat.is_dir`
- fun open_wo: OFStream
+ fun open_wo: FileWriter
do
# TODO manage streams error when they are merged
- return new OFStream.open(path)
+ return new FileWriter.open(path)
end
+ # Read all the content of the file
+ #
+ # ~~~
+ # var content = "/etc/issue".to_path.read_all
+ # print content
+ # ~~~
+ #
+ # See `Reader::read_all` for details.
+ fun read_all: String
+ do
+ var s = open_ro
+ var res = s.read_all
+ s.close
+ return res
+ end
+
+ # Read all the lines of the file
+ #
+ # ~~~
+ # var lines = "/etc/passwd".to_path.read_lines
+ #
+ # print "{lines.length} users"
+ #
+ # for l in lines do
+ # var fields = l.split(":")
+ # print "name={fields[0]} uid={fields[2]}"
+ # end
+ # ~~~
+ #
+ # See `Reader::read_lines` for details.
+ fun read_lines: Array[String]
+ do
+ var s = open_ro
+ var res = s.read_lines
+ s.close
+ return res
+ end
+
+ # Return an iterator on each line of the file
+ #
+ # ~~~
+ # for l in "/etc/passwd".to_path.each_line do
+ # var fields = l.split(":")
+ # print "name={fields[0]} uid={fields[2]}"
+ # end
+ # ~~~
+ #
+ # Note: the stream is automatically closed at the end of the file (see `LineIterator::close_on_finish`)
+ #
+ # See `Reader::each_line` for details.
+ fun each_line: LineIterator
+ do
+ var s = open_ro
+ var res = s.each_line
+ res.close_on_finish = true
+ return res
+ end
+
+
# Lists the name of the files contained within the directory at `path`
#
# Require: `exists and is_dir`
# trainling "/" is removed
#
# Note that the method only wonrk on the string:
+ #
# * no I/O access is performed
# * the validity of the path is not checked
#
- # assert "some/./complex/../../path/from/../to/a////file//".simplify_path == "path/to/a/file"
- # assert "../dir/file".simplify_path == "../dir/file"
- # assert "dir/../../".simplify_path == ".."
- # assert "dir/..".simplify_path == "."
- # assert "//absolute//path/".simplify_path == "/absolute/path"
- # assert "//absolute//../".simplify_path == "/"
+ # ~~~
+ # assert "some/./complex/../../path/from/../to/a////file//".simplify_path == "path/to/a/file"
+ # assert "../dir/file".simplify_path == "../dir/file"
+ # assert "dir/../../".simplify_path == ".."
+ # assert "dir/..".simplify_path == "."
+ # assert "//absolute//path/".simplify_path == "/absolute/path"
+ # assert "//absolute//../".simplify_path == "/"
+ # ~~~
fun simplify_path: String
do
var a = self.split_with("/")
redef class Sys
- init do
- if stdout isa FStream then stdout.as(FStream).set_buffering_mode(256, buffer_mode_line)
- end
-
# Standard input
- var stdin: PollableIStream = new Stdin is protected writable
+ var stdin: PollableReader = new Stdin is protected writable, lazy
# Standard output
- var stdout: OStream = new Stdout is protected writable
+ var stdout: Writer = new Stdout is protected writable, lazy
# Standard output for errors
- var stderr: OStream = new Stderr is protected writable
+ var stderr: Writer = new Stderr is protected writable, lazy
# Enumeration for buffer mode full (flushes when buffer is full)
fun buffer_mode_full: Int is extern "file_Sys_Sys_buffer_mode_full_0"
# returns first available stream to read or write to
# return null on interruption (possibly a signal)
- protected fun poll( streams : Sequence[FStream] ) : nullable FStream
+ protected fun poll( streams : Sequence[FileStream] ) : nullable FileStream
do
var in_fds = new Array[Int]
var out_fds = new Array[Int]
- var fd_to_stream = new HashMap[Int,FStream]
+ var fd_to_stream = new HashMap[Int,FileStream]
for s in streams do
var fd = s.fd
- if s isa IFStream then in_fds.add( fd )
- if s isa OFStream then out_fds.add( fd )
+ if s isa FileReader then in_fds.add( fd )
+ if s isa FileWriter then out_fds.add( fd )
fd_to_stream[fd] = s
end