X-Git-Url: http://nitlanguage.org diff --git a/lib/core/file.nit b/lib/core/file.nit index baa3403..643fe08 100644 --- a/lib/core/file.nit +++ b/lib/core/file.nit @@ -898,9 +898,7 @@ redef class Text # return true if a file with this names exists fun file_exists: Bool do return to_cstring.file_exists -end -redef class String # The status of a file. see POSIX stat(2). fun file_stat: nullable FileStat do @@ -943,14 +941,14 @@ redef class String if extension == null then extension = file_extension if extension == null then - return self + return self.to_s else extension = ".{extension}" end if has_suffix(extension) then - return substring(0, length - extension.length) + return substring(0, length - extension.length).to_s end - return self + return self.to_s end # Extract the basename of a path and strip the `extension` @@ -963,35 +961,33 @@ redef class String # assert "path/to".basename(".ext") == "to" # assert "path/to/".basename(".ext") == "to" # assert "path/to".basename == "to" - # assert "path".basename("") == "path" - # assert "/path".basename("") == "path" - # assert "/".basename("") == "/" - # assert "".basename("") == "" + # assert "path".basename == "path" + # assert "/path".basename == "path" + # assert "/".basename == "/" + # assert "".basename == "" + # + # On Windows, '\' are replaced by '/': + # + # ~~~nitish + # assert "C:\\path\\to\\a_file.ext".basename(".ext") == "a_file" + # assert "C:\\".basename == "C:" + # ~~~ fun basename(extension: nullable String): String do var n = self - if is_windows then - var l = length - 1 # Index of the last char - while l > 0 and (self.chars[l] == '/' or chars[l] == '\\') do l -= 1 # remove all trailing `/` - if l == 0 then return "/" - var pos = chars.last_index_of_from('/', l) - pos = pos.max(last_index_of_from('\\', l)) - if pos >= 0 then - n = substring(pos+1, l-pos) - end - else - var l = length - 1 # Index of the last char - while l > 0 and self.chars[l] == '/' do l -= 1 # remove all trailing `/` - if l == 0 then return "/" - var pos = chars.last_index_of_from('/', l) - if pos >= 0 then - n = substring(pos+1, l-pos) - end + if is_windows then n = n.replace("\\", "/") + + var l = length - 1 # Index of the last char + while l > 0 and self.chars[l] == '/' do l -= 1 # remove all trailing `/` + if l == 0 then return "/" + var pos = chars.last_index_of_from('/', l) + if pos >= 0 then + n = substring(pos+1, l-pos) end if extension != null then return n.strip_extension(extension) - else return n + else return n.to_s end # Extract the dirname of a path @@ -1004,13 +1000,23 @@ redef class String # assert "/path".dirname == "/" # assert "/".dirname == "/" # assert "".dirname == "." + # + # On Windows, '\' are replaced by '/': + # + # ~~~nitish + # assert "C:\\path\\to\\a_file.ext".dirname == "C:/path/to" + # assert "C:\\file".dirname == "C:" + # ~~~ fun dirname: String do + var s = self + if is_windows then s = s.replace("\\", "/") + var l = length - 1 # Index of the last char - while l > 0 and self.chars[l] == '/' do l -= 1 # remove all trailing `/` - var pos = chars.last_index_of_from('/', l) + while l > 0 and s.chars[l] == '/' do l -= 1 # remove all trailing `/` + var pos = s.chars.last_index_of_from('/', l) if pos > 0 then - return substring(0, pos) + return s.substring(0, pos).to_s else if pos == 0 then return "/" else @@ -1055,10 +1061,18 @@ redef class String # assert "./../dir".simplify_path == "../dir" # assert "./dir".simplify_path == "dir" # ~~~ + # + # On Windows, '\' are replaced by '/': + # + # ~~~nitish + # assert "C:\\some\\.\\complex\\../../path/to/a_file.ext".simplify_path == "C:/path/to/a_file.ext" + # assert "C:\\".simplify_path == "C:" + # ~~~ fun simplify_path: String do - var path_sep = if is_windows then "\\" else "/" - var a = self.split_with(path_sep) + var s = self + if is_windows then s = s.replace("\\", "/") + var a = s.split_with("/") var a2 = new Array[String] for x in a do if x == "." and not a2.is_empty then continue # skip `././` @@ -1099,11 +1113,11 @@ redef class String # Note: You may want to use `simplify_path` on the result. # # Note: This method works only with POSIX paths. - fun join_path(path: String): String + fun join_path(path: Text): String do - if path.is_empty then return self - if self.is_empty then return path - if path.chars[0] == '/' then return path + if path.is_empty then return self.to_s + if self.is_empty then return path.to_s + if path.chars[0] == '/' then return path.to_s if self.last == '/' then return "{self}{path}" return "{self}/{path}" end @@ -1118,7 +1132,7 @@ redef class String # assert "".to_program_name == "./" # At least, your shell will detect the error. fun to_program_name: String do if self.has_prefix("/") then - return self + return self.to_s else return "./{self}" end @@ -1138,7 +1152,7 @@ redef class String # var b = "/bar" # var c = "baz/foobar" # assert a/b/c == "/bar/baz/foobar" - fun /(path: String): String do return join_path(path) + fun /(path: Text): String do return join_path(path) # Returns the relative path needed to go from `self` to `dest`. # @@ -1183,6 +1197,7 @@ redef class String # assert "/" + "/".relpath(".") == getcwd fun relpath(dest: String): String do + # TODO windows support var cwd = getcwd var from = (cwd/self).simplify_path.split("/") if from.last.is_empty then from.pop # case for the root directory @@ -1215,8 +1230,10 @@ redef class String fun mkdir(mode: nullable Int): nullable Error do mode = mode or else 0o777 + var s = self + if is_windows then s = s.replace("\\", "/") - var dirs = self.split_with("/") + var dirs = s.split_with("/") var path = new FlatBuffer if dirs.is_empty then return null if dirs[0].is_empty then @@ -1235,7 +1252,7 @@ redef class String error = new IOError("Cannot create directory `{path}`: {sys.errno.strerror}") end end - var res = self.to_cstring.file_mkdir(mode) + var res = s.to_cstring.file_mkdir(mode) if not res and error == null then error = new IOError("Cannot create directory `{path}`: {sys.errno.strerror}") end @@ -1299,7 +1316,7 @@ redef class String do var last_slash = chars.last_index_of('.') if last_slash > 0 then - return substring( last_slash+1, length ) + return substring( last_slash+1, length ).to_s else return null end @@ -1356,29 +1373,19 @@ redef class FlatString end redef fun basename(extension) do + var s = self + if is_windows then s = s.replace("\\", "/").as(FlatString) + var bname - if is_windows then - var l = last_byte - var its = _items - var min = _first_byte - var sl = '/'.ascii - var ls = '\\'.ascii - while l > min and (its[l] == sl or its[l] == ls) do l -= 1 - if l == min then return "\\" - var ns = l - while ns >= min and its[ns] != sl and its[ns] != ls do ns -= 1 - bname = new FlatString.with_infos(its, l - ns, ns + 1) - else - var l = last_byte - var its = _items - var min = _first_byte - var sl = '/'.ascii - while l > min and its[l] == sl do l -= 1 - if l == min then return "/" - var ns = l - while ns >= min and its[ns] != sl do ns -= 1 - bname = new FlatString.with_infos(its, l - ns, ns + 1) - end + var l = s.last_byte + var its = s._items + var min = s._first_byte + var sl = '/'.ascii + while l > min and its[l] == sl do l -= 1 + if l == min then return "/" + var ns = l + while ns >= min and its[ns] != sl do ns -= 1 + bname = new FlatString.with_infos(its, l - ns, ns + 1) return if extension != null then bname.strip_extension(extension) else bname end @@ -1509,7 +1516,12 @@ private extern class NativeFile `{ FILE* `} `} fun io_write(buf: CString, from, len: Int): Int `{ - return fwrite(buf+from, 1, len, self); + size_t res = fwrite(buf+from, 1, len, self); +#ifdef _WIN32 + // Force flushing buffer because end of line does not trigger a flush + fflush(self); +#endif + return (long)res; `} fun write_byte(value: Byte): Int `{