# 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
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`
# 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
# 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
# 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 `././`
# 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
# 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
# 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`.
#
# 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
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
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
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
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
`}
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 `{