Merge branch 'ni' into wip
[nit.git] / lib / standard / file.nit
index c564aff..00fbb32 100644 (file)
@@ -68,6 +68,8 @@ class IFStream
        super BufferedIStream
        # Misc
 
+       # Open the same file again.
+       # The original path is reused, therefore the reopened file can be a different file.
        fun reopen
        do
                if not eof then close
@@ -83,7 +85,6 @@ class IFStream
                _end_reached = true
        end
 
-       # Fill the internal read buffer. Needed by read operations.
        redef fun fill_buffer
        do
                var nb = _file.io_read(_buffer._items, _buffer._capacity)
@@ -116,7 +117,6 @@ class OFStream
        super FStream
        super OStream
        
-       # Write a string.
        redef fun write(s)
        do
                assert _writable
@@ -195,8 +195,10 @@ redef class String
 
        fun file_stat: FileStat do return to_cstring.file_stat
 
+       # Remove a file, return true if success
        fun file_delete: Bool do return to_cstring.file_delete
 
+       # remove the trailing extension "ext"
        fun strip_extension(ext: String): String
        do
                if has_suffix(ext) then
@@ -205,6 +207,7 @@ redef class String
                return self
        end
 
+       # Extract the basename of a path and remove the extension
        fun basename(ext: String): String
        do
                var pos = last_index_of_from('/', _length - 1)
@@ -215,6 +218,7 @@ redef class String
                return n.strip_extension(ext)
        end
 
+       # Extract the dirname of a path
        fun dirname: String
        do
                var pos = last_index_of_from('/', _length - 1)
@@ -225,14 +229,33 @@ redef class String
                end
        end
 
-       fun file_path: String
+       # Simplify a file path by remove useless ".", removing "//", and resolving ".."
+       # ".." are not resolved if they start the path
+       # starting "/" is not removed
+       # trainling "/" is removed
+       #
+       # Note that the method only wonrk on the string:
+       #  * no I/O access is performed
+       #  * the validity of the path is not checked
+       #
+       #     "some/./complex/../../path/from/../to/a////file//".simplify_path  # -> "path/to/a/file"
+       #     "../dir/file" # -> "../dir/file"
+       #     "dir/../../" # -> ".."
+       #     "//absolute//path/" # -> "/absolute/path"
+       fun simplify_path: String
        do
-               var l = _length
-               var pos = last_index_of_from('/', l - 1)
-               if pos >= 0 then
-                       return substring(0, pos)
+               var a = self.split_with("/")
+               var a2 = new Array[String]
+               for x in a do
+                       if x == "." then continue
+                       if x == "" and not a2.is_empty then continue
+                       if x == ".." and not a2.is_empty then
+                               a2.pop
+                               continue
+                       end
+                       a2.push(x)
                end
-               return "."
+               return a2.join("/")
        end
 
        # Create a directory (and all intermediate directories if needed)
@@ -252,6 +275,17 @@ redef class String
                        path.to_s.to_cstring.file_mkdir
                end
        end
+
+       # Return right-most extension (without the dot)
+       fun file_extension : nullable String
+       do
+               var last_slash = last_index_of('.')
+               if last_slash >= 0 then
+                       return substring( last_slash+1, length )
+               else
+                       return null
+               end
+       end
 end
 
 redef class NativeString