Merge: Added contributing guidelines and link from readme
[nit.git] / lib / core / file.nit
index fd848e1..8bf8078 100644 (file)
@@ -49,23 +49,24 @@ abstract class FileStream
        # Return null in case of error
        fun file_stat: nullable FileStat
        do
-               var stat = _file.file_stat
+               var stat = _file.as(not null).file_stat
                if stat.address_is_null then return null
                return new FileStat(stat)
        end
 
        # File descriptor of this file
-       fun fd: Int do return _file.fileno
+       fun fd: Int do return _file.as(not null).fileno
 
        redef fun close
        do
-               if _file == null then return
-               if _file.address_is_null then
+               var file = _file
+               if file == null then return
+               if file.address_is_null then
                        if last_error != null then return
                        last_error = new IOError("Cannot close unopened file")
                        return
                end
-               var i = _file.io_close
+               var i = file.io_close
                if i != 0 then
                        last_error = new IOError("Close failed due to error {sys.errno.strerror}")
                end
@@ -83,7 +84,7 @@ abstract class FileStream
        # * `buffer_mode_none`
        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
+               if _file.as(not null).set_buffering_type(buf_size, mode) != 0 then
                        last_error = new IOError("Error while changing buffering type for FileStream, returned error {sys.errno.strerror}")
                end
        end
@@ -105,10 +106,10 @@ class FileReader
        #     assert l == f.read_line
        fun reopen
        do
-               if not eof and not _file.address_is_null then close
+               if not eof and not _file.as(not null).address_is_null then close
                last_error = null
-               _file = new NativeFile.io_open_read(path.to_cstring)
-               if _file.address_is_null then
+               _file = new NativeFile.io_open_read(path.as(not null).to_cstring)
+               if _file.as(not null).address_is_null then
                        last_error = new IOError("Cannot open `{path.as(not null)}`: {sys.errno.strerror}")
                        end_reached = true
                        return
@@ -126,8 +127,8 @@ class FileReader
 
        redef fun fill_buffer
        do
-               var nb = _file.io_read(_buffer, _buffer_capacity)
-               if last_error == null and _file.ferror then
+               var nb = _file.as(not null).io_read(_buffer, _buffer_capacity)
+               if last_error == null and _file.as(not null).ferror then
                        last_error = new IOError("Cannot read `{path.as(not null)}`: {sys.errno.strerror}")
                        end_reached = true
                end
@@ -158,7 +159,7 @@ class FileReader
                self.path = path
                prepare_buffer(100)
                _file = new NativeFile.io_open_read(path.to_cstring)
-               if _file.address_is_null then
+               if _file.as(not null).address_is_null then
                        last_error = new IOError("Cannot open `{path}`: {sys.errno.strerror}")
                        end_reached = true
                end
@@ -171,7 +172,7 @@ class FileReader
                self.path = ""
                prepare_buffer(1)
                _file = fd.fd_to_stream(read_only)
-               if _file.address_is_null then
+               if _file.as(not null).address_is_null then
                        last_error = new IOError("Error: Converting fd {fd} to stream failed with '{sys.errno.strerror}'")
                        end_reached = true
                end
@@ -187,7 +188,7 @@ class FileReader
        end
 
        private fun native_poll_in(fd: Int): Int `{
-               struct pollfd fds = {fd, POLLIN, 0};
+               struct pollfd fds = {(int)fd, POLLIN, 0};
                return poll(&fds, 1, 0);
        `}
 end
@@ -223,13 +224,13 @@ class FileWriter
                        last_error = new IOError("Cannot write to non-writable stream")
                        return
                end
-               if _file.address_is_null then
+               if _file.as(not null).address_is_null then
                        last_error = new IOError("Writing on a null stream")
                        _is_writable = false
                        return
                end
 
-               var err = _file.write_byte(value)
+               var err = _file.as(not null).write_byte(value)
                if err != 1 then
                        # Big problem
                        last_error = new IOError("Problem writing a byte: {err}")
@@ -251,12 +252,12 @@ class FileWriter
                        last_error = new IOError("Cannot write to non-writable stream")
                        return
                end
-               if _file.address_is_null then
+               if _file.as(not null).address_is_null then
                        last_error = new IOError("Writing on a null stream")
                        _is_writable = false
                        return
                end
-               var err = _file.io_write(native, from, len)
+               var err = _file.as(not null).io_write(native, from, len)
                if err != len then
                        # Big problem
                        last_error = new IOError("Problem in writing : {err} {len} \n")
@@ -269,7 +270,7 @@ class FileWriter
                _file = new NativeFile.io_open_write(path.to_cstring)
                self.path = path
                _is_writable = true
-               if _file.address_is_null then
+               if _file.as(not null).address_is_null then
                        last_error = new IOError("Cannot open `{path}`: {sys.errno.strerror}")
                        is_writable = false
                end
@@ -280,7 +281,7 @@ class FileWriter
                self.path = ""
                _file = fd.fd_to_stream(wipe_write)
                _is_writable = true
-                if _file.address_is_null then
+                if _file.as(not null).address_is_null then
                         last_error = new IOError("Error: Opening stream from file descriptor {fd} failed with '{sys.errno.strerror}'")
                        _is_writable = false
                end
@@ -292,7 +293,7 @@ redef class Int
        #
        # NOTE: The `mode` specified must be compatible with the one used in the file descriptor.
        private fun fd_to_stream(mode: NativeString): NativeFile `{
-               return fdopen(self, mode);
+               return fdopen((int)self, mode);
        `}
 end
 
@@ -498,8 +499,8 @@ class Path
                var output = dest.open_wo
 
                while not input.eof do
-                       var buffer = input.read(1024)
-                       output.write buffer
+                       var buffer = input.read_bytes(1024)
+                       output.write_bytes buffer
                end
 
                input.close
@@ -663,6 +664,19 @@ class Path
                return res
        end
 
+       # Is `self` the path to an existing directory ?
+       #
+       # ~~~nit
+       # assert ".".to_path.is_dir
+       # assert not "/etc/issue".to_path.is_dir
+       # assert not "/should/not/exist".to_path.is_dir
+       # ~~~
+       fun is_dir: Bool do
+               var st = stat
+               if st == null then return false
+               return st.is_dir
+       end
+
        # Delete a directory and all of its content
        #
        # Does not go through symbolic links and may get stuck in a cycle if there
@@ -1145,11 +1159,16 @@ redef class String
 
        # Create a directory (and all intermediate directories if needed)
        #
+       # The optional `mode` parameter specifies the permissions of the directory,
+       # the default value is `0o777`.
+       #
        # Return an error object in case of error.
        #
        #    assert "/etc/".mkdir != null
-       fun mkdir: nullable Error
+       fun mkdir(mode: nullable Int): nullable Error
        do
+               mode = mode or else 0o777
+
                var dirs = self.split_with("/")
                var path = new FlatBuffer
                if dirs.is_empty then return null
@@ -1162,7 +1181,7 @@ redef class String
                        if d.is_empty then continue
                        path.append(d)
                        path.add('/')
-                       var res = path.to_s.to_cstring.file_mkdir
+                       var res = path.to_s.to_cstring.file_mkdir(mode)
                        if not res and error == null then
                                error = new IOError("Cannot create directory `{path}`: {sys.errno.strerror}")
                        end
@@ -1271,7 +1290,7 @@ redef class FlatString
 
        redef fun file_extension do
                var its = _items
-               var p = _last_byte
+               var p = last_byte
                var c = its[p]
                var st = _first_byte
                while p >= st and c != '.'.ascii do
@@ -1279,12 +1298,12 @@ redef class FlatString
                        c = its[p]
                end
                if p <= st then return null
-               var ls = _last_byte
-               return new FlatString.with_infos(its, ls - p, p + 1, ls)
+               var ls = last_byte
+               return new FlatString.with_infos(its, ls - p, p + 1)
        end
 
        redef fun basename(extension) do
-               var l = _last_byte
+               var l = last_byte
                var its = _items
                var min = _first_byte
                var sl = '/'.ascii
@@ -1292,7 +1311,7 @@ redef class FlatString
                if l == min then return "/"
                var ns = l
                while ns >= min and its[ns] != sl do ns -= 1
-               var bname = new FlatString.with_infos(its, l - ns, ns + 1, l)
+               var bname = new FlatString.with_infos(its, l - ns, ns + 1)
 
                return if extension != null then bname.strip_extension(extension) else bname
        end
@@ -1326,7 +1345,7 @@ redef class NativeString
                return stat_element;
        `}
 
-       private fun file_mkdir: Bool `{ return !mkdir(self, 0777); `}
+       private fun file_mkdir(mode: Int): Bool `{ return !mkdir(self, mode); `}
 
        private fun rmdir: Bool `{ return !rmdir(self); `}
 
@@ -1414,8 +1433,8 @@ private extern class NativeFile `{ FILE* `}
        fun flush: Int `{ return fflush(self); `}
 
        # Used to specify how the buffering will be handled for the current stream.
-       fun set_buffering_type(buf_length: Int, mode: Int): Int `{
-               return setvbuf(self, NULL, mode, buf_length);
+       fun set_buffering_type(buf_length, mode: Int): Int `{
+               return setvbuf(self, NULL, (int)mode, buf_length);
        `}
 
        new io_open_read(path: NativeString) `{ return fopen(path, "r"); `}
@@ -1499,15 +1518,14 @@ redef class Sys
                int first_polled_fd = -1;
                int result;
 
-               in_len = Array_of_Int_length( in_fds );
-               out_len = Array_of_Int_length( out_fds );
+               in_len = (int)Array_of_Int_length( in_fds );
+               out_len = (int)Array_of_Int_length( out_fds );
                total_len = in_len + out_len;
                c_fds = malloc( sizeof(struct pollfd) * total_len );
 
                /* input streams */
                for ( i=0; i<in_len; i ++ ) {
-                       int fd;
-                       fd = Array_of_Int__index( in_fds, i );
+                       int fd = (int)Array_of_Int__index( in_fds, i );
 
                        c_fds[i].fd = fd;
                        c_fds[i].events = POLLIN;
@@ -1515,8 +1533,7 @@ redef class Sys
 
                /* output streams */
                for ( i=0; i<out_len; i ++ ) {
-                       int fd;
-                       fd = Array_of_Int__index( out_fds, i );
+                       int fd = (int)Array_of_Int__index( out_fds, i );
 
                        c_fds[i].fd = fd;
                        c_fds[i].events = POLLOUT;