X-Git-Url: http://nitlanguage.org diff --git a/lib/standard/file.nit b/lib/standard/file.nit index 8af3c70..42eca14 100644 --- a/lib/standard/file.nit +++ b/lib/standard/file.nit @@ -42,7 +42,17 @@ abstract class FileStream private var file: nullable NativeFile = null # The status of a file. see POSIX stat(2). - fun file_stat: NativeFileStat do return _file.file_stat + # + # var f = new FileReader.open("/etc/issue") + # assert f.file_stat.is_file + # + # Return null in case of error + fun file_stat: nullable FileStat + do + var stat = _file.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 @@ -330,6 +340,10 @@ class Path # # Returns `null` if there is no file at `self`. # + # assert "/etc/".to_path.stat.is_dir + # assert "/etc/issue".to_path.stat.is_file + # assert "/fail/does not/exist".to_path.stat == null + # # ~~~ # var p = "/tmp/".to_path # var stat = p.stat @@ -481,7 +495,7 @@ class Path end # Delete the directory itself - if ok then path.to_cstring.rmdir + if ok then ok = path.to_cstring.rmdir and ok return ok end @@ -523,6 +537,11 @@ class FileStat return stat.atime end + # Returns the last access time + # + # alias for `last_access_time` + fun atime: Int do return last_access_time + # Returns the last modification time in seconds since Epoch fun last_modification_time: Int do @@ -530,6 +549,12 @@ class FileStat return stat.mtime end + # Returns the last modification time + # + # alias for `last_modification_time` + fun mtime: Int do return last_modification_time + + # Size of the file at `path` fun size: Int do @@ -537,13 +562,16 @@ class FileStat return stat.size end - # Is this a regular file and not a device file, pipe, socket, etc.? + # Is self a regular file and not a device file, pipe, socket, etc.? fun is_file: Bool do assert not finalized return stat.is_reg end + # Alias for `is_file` + fun is_reg: Bool do return is_file + # Is this a directory? fun is_dir: Bool do @@ -567,6 +595,11 @@ class FileStat return stat.ctime end + # Returns the last status change time + # + # alias for `last_status_change_time` + fun ctime: Int do return last_status_change_time + # Returns the permission bits of file fun mode: Int do @@ -613,10 +646,20 @@ redef class String fun file_exists: Bool do return to_cstring.file_exists # The status of a file. see POSIX stat(2). - fun file_stat: NativeFileStat do return to_cstring.file_stat + fun file_stat: nullable FileStat + do + var stat = to_cstring.file_stat + if stat.address_is_null then return null + return new FileStat(stat) + end # The status of a file or of a symlink. see POSIX lstat(2). - fun file_lstat: NativeFileStat do return to_cstring.file_lstat + fun file_lstat: nullable FileStat + do + var stat = to_cstring.file_lstat + if stat.address_is_null then return null + return new FileStat(stat) + end # Remove a file, return true if success fun file_delete: Bool do return to_cstring.file_delete @@ -860,28 +903,47 @@ redef class String end # Create a directory (and all intermediate directories if needed) - fun mkdir + # + # Return an error object in case of error. + # + # assert "/etc/".mkdir != null + fun mkdir: nullable Error do var dirs = self.split_with("/") var path = new FlatBuffer - if dirs.is_empty then return + if dirs.is_empty then return null if dirs[0].is_empty then # it was a starting / path.add('/') end + var error: nullable Error = null for d in dirs do if d.is_empty then continue path.append(d) path.add('/') - path.to_s.to_cstring.file_mkdir + var res = path.to_s.to_cstring.file_mkdir + if not res and error == null then + error = new IOError("Cannot create directory `{path}`: {sys.errno.strerror}") + end end + return error end # Delete a directory and all of its content, return `true` on success # # Does not go through symbolic links and may get stuck in a cycle if there # is a cycle in the filesystem. - fun rmdir: Bool do return to_path.rmdir + # + # Return an error object in case of error. + # + # assert "/fail/does not/exist".rmdir != null + fun rmdir: nullable Error + do + var res = to_path.rmdir + if res then return null + var error = new IOError("Cannot change remove `{self}`: {sys.errno.strerror}") + return error + end # Change the current working directory # @@ -890,8 +952,18 @@ redef class String # "..".chdir # assert getcwd == "/" # - # TODO: errno - fun chdir do to_cstring.file_chdir + # Return an error object in case of error. + # + # assert "/etc".chdir == null + # assert "/fail/does no/exist".chdir != null + # assert getcwd == "/etc" # unchanger + fun chdir: nullable Error + do + var res = to_cstring.file_chdir + if res then return null + var error = new IOError("Cannot change directory to `{self}`: {sys.errno.strerror}") + return error + end # Return right-most extension (without the dot) # @@ -921,7 +993,17 @@ redef class String end end - # returns files contained within the directory represented by self + # Returns entries contained within the directory represented by self. + # + # var files = "/etc".files + # assert files.has("issue") + # + # Returns an empty array in case of error + # + # files = "/etc/issue".files + # assert files.is_empty + # + # TODO find a better way to handle errors and to give them back to the user. fun files: Array[String] is extern import Array[String], Array[String].add, NativeString.to_s, String.to_cstring `{ char *dir_path; DIR *dir; @@ -929,8 +1011,11 @@ redef class String dir_path = String_to_cstring( recv ); if ((dir = opendir(dir_path)) == NULL) { - perror( dir_path ); - exit( 1 ); + //perror( dir_path ); + //exit( 1 ); + Array_of_String results; + results = new_Array_of_String(); + return results; } else { @@ -966,14 +1051,14 @@ redef class NativeString return stat_element; `} private fun file_mkdir: Bool is extern "string_NativeString_NativeString_file_mkdir_0" - private fun rmdir: Bool `{ return rmdir(recv); `} + private fun rmdir: Bool `{ return !rmdir(recv); `} private fun file_delete: Bool is extern "string_NativeString_NativeString_file_delete_0" - private fun file_chdir is extern "string_NativeString_NativeString_file_chdir_0" + private fun file_chdir: Bool is extern "string_NativeString_NativeString_file_chdir_0" private fun file_realpath: NativeString is extern "file_NativeString_realpath" end # This class is system dependent ... must reify the vfs -extern class NativeFileStat `{ struct stat * `} +private extern class NativeFileStat `{ struct stat * `} # Returns the permission bits of file fun mode: Int is extern "file_FileStat_FileStat_mode_0" # Returns the last access time @@ -1117,30 +1202,30 @@ redef class Sys end # Print `objects` on the standard output (`stdout`). -protected fun printn(objects: Object...) +fun printn(objects: Object...) do sys.stdout.write(objects.to_s) end # Print an `object` on the standard output (`stdout`) and add a newline. -protected fun print(object: Object) +fun print(object: Object) do sys.stdout.write(object.to_s) sys.stdout.write("\n") end # Read a character from the standard input (`stdin`). -protected fun getc: Char +fun getc: Char do return sys.stdin.read_char.ascii end # Read a line from the standard input (`stdin`). -protected fun gets: String +fun gets: String do return sys.stdin.read_line end # Return the working (current) directory -protected fun getcwd: String do return file_getcwd.to_s +fun getcwd: String do return file_getcwd.to_s private fun file_getcwd: NativeString is extern "string_NativeString_NativeString_file_getcwd_0"