lib/file: revamp `poll_in` to use in `FileReader`
[nit.git] / lib / standard / file.nit
index b06a93d..e5fc85b 100644 (file)
@@ -109,7 +109,7 @@ class FileReader
                last_error = null
                _file = new NativeFile.io_open_read(path.to_cstring)
                if _file.address_is_null then
-                       last_error = new IOError("Error: Opening file at '{path.as(not null)}' failed with '{sys.errno.strerror}'")
+                       last_error = new IOError("Cannot open `{path.as(not null)}`: {sys.errno.strerror}")
                        end_reached = true
                        return
                end
@@ -127,6 +127,10 @@ class FileReader
        redef fun fill_buffer
        do
                var nb = _file.io_read(_buffer, _buffer_capacity)
+               if last_error == null and _file.ferror then
+                       last_error = new IOError("Cannot read `{path.as(not null)}`: {sys.errno.strerror}")
+                       end_reached = true
+               end
                if nb <= 0 then
                        end_reached = true
                        nb = 0
@@ -155,7 +159,7 @@ class FileReader
                prepare_buffer(10)
                _file = new NativeFile.io_open_read(path.to_cstring)
                if _file.address_is_null then
-                       last_error = new IOError("Error: Opening file at '{path}' failed with '{sys.errno.strerror}'")
+                       last_error = new IOError("Cannot open `{path}`: {sys.errno.strerror}")
                        end_reached = true
                end
        end
@@ -172,6 +176,20 @@ class FileReader
                        end_reached = true
                end
        end
+
+       redef fun poll_in
+       do
+               var res = native_poll_in(fd)
+               if res == -1 then
+                       last_error = new IOError(errno.to_s)
+                       return false
+               else return res > 0
+       end
+
+       private fun native_poll_in(fd: Int): Int `{
+               struct pollfd fds = {fd, POLLIN, 0};
+               return poll(&fds, 1, 0);
+       `}
 end
 
 # `Stream` that can write to a File
@@ -252,7 +270,7 @@ class FileWriter
                self.path = path
                _is_writable = true
                if _file.address_is_null then
-                       last_error = new IOError("Error: Opening file at '{path}' failed with '{sys.errno.strerror}'")
+                       last_error = new IOError("Cannot open `{path}`: {sys.errno.strerror}")
                        is_writable = false
                end
        end
@@ -301,16 +319,6 @@ class Stdin
                path = "/dev/stdin"
                prepare_buffer(1)
        end
-
-       redef fun poll_in `{
-               struct pollfd fd = {0, POLLIN, 0};
-               int res = poll(&fd, 1, 0);
-               if (res == -1) {
-                       perror("Error poll stdin");
-                       exit(EXIT_FAILURE);
-               }
-               return res > 0;
-       `}
 end
 
 # Standard output stream.
@@ -370,8 +378,42 @@ class Path
        # var path = "/tmp/somefile".to_path
        # assert path.filename == "somefile"
        # ~~~
+       #
+       # The result does not depend of the file system, thus is cached for efficiency.
        var filename: String = path.basename is lazy
 
+       # The path simplified by removing useless `.`, removing `//`, and resolving `..`
+       #
+       # ~~~
+       # var path = "somedir/./tmp/../somefile".to_path
+       # assert path.simplified.to_s == "somedir/somefile"
+       # ~~~
+       #
+       # See `String:simplify_path` for details.
+       #
+       # The result does not depend of the file system, thus is cached for efficiency.
+       var simplified: Path is lazy do
+               var res = path.simplify_path.to_path
+               res.simplified = res
+               return res
+       end
+
+       # Return the directory part of the path.
+       #
+       # ~~~
+       # var path = "/foo/bar/baz".to_path
+       # assert path.dir.to_s == "/foo/bar"
+       # assert path.dir.dir.to_s == "/foo"
+       # assert path.dir.dir.dir.to_s == "/"
+       # ~~~
+       #
+       # See `String:dirname` for details.
+       #
+       # The result does not depend of the file system, thus is cached for efficiency.
+       var dir: Path is lazy do
+               return path.dirname.to_path
+       end
+
        # Last error produced by I/O operations.
        #
        # ~~~
@@ -660,8 +702,8 @@ class Path
                end
        end
 
-       redef fun ==(other) do return other isa Path and path.simplify_path == other.path.simplify_path
-       redef fun hash do return path.simplify_path.hash
+       redef fun ==(other) do return other isa Path and simplified.path == other.simplified.path
+       redef fun hash do return simplified.path.hash
 end
 
 # Information on a file
@@ -802,7 +844,7 @@ redef class Text
 
        private fun write_native_to(s: FileWriter)
        do
-               for i in substrings do s.write_native(i.to_cstring, 0, i.length)
+               for i in substrings do s.write_native(i.to_cstring, 0, i.bytelen)
        end
 end
 
@@ -1221,7 +1263,7 @@ end
 redef class FlatString
        redef fun write_native_to(s)
        do
-               s.write_native(items, index_from, length)
+               s.write_native(items, first_byte, bytelen)
        end
 end
 
@@ -1333,6 +1375,8 @@ private extern class NativeFile `{ FILE* `}
                return 0;
        `}
 
+       fun ferror: Bool `{ return ferror(self); `}
+
        fun fileno: Int `{ return fileno(self); `}
 
        # Flushes the buffer, forcing the write operation