Canonicalize path for comparison * Handles path string redundancies * Does not test existence of path
To be replaced by realpath/_fullname in stdlib_os
FIXME: Lot’s of ugly hacks following here
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
character(len=*), | intent(in) | :: | path |
function canon_path(path)
character(len=*), intent(in) :: path
character(len=:), allocatable :: canon_path
character(len=:), allocatable :: nixpath
integer :: istart, iend, nn, last
logical :: is_path, absolute
nixpath = unix_path(path)
istart = 0
nn = 0
iend = 0
absolute = nixpath(1:1) == "/"
if (absolute) then
canon_path = "/"
else
canon_path = ""
end if
do while(iend < len(nixpath))
call next(nixpath, istart, iend, is_path)
if (is_path) then
select case(nixpath(istart:iend))
case(".", "") ! always drop empty paths
case("..")
if (nn > 0) then
last = scan(canon_path(:len(canon_path)-1), "/", back=.true.)
canon_path = canon_path(:last)
nn = nn - 1
else
if (.not. absolute) then
canon_path = canon_path // nixpath(istart:iend) // "/"
end if
end if
case default
nn = nn + 1
canon_path = canon_path // nixpath(istart:iend) // "/"
end select
end if
end do
if (len(canon_path) == 0) canon_path = "."
if (len(canon_path) > 1 .and. canon_path(len(canon_path):) == "/") then
canon_path = canon_path(:len(canon_path)-1)
end if
contains
subroutine next(string, istart, iend, is_path)
character(len=*), intent(in) :: string
integer, intent(inout) :: istart
integer, intent(inout) :: iend
logical, intent(inout) :: is_path
integer :: ii, nn
character :: tok
nn = len(string)
if (iend >= nn) then
istart = nn
iend = nn
return
end if
ii = min(iend + 1, nn)
tok = string(ii:ii)
is_path = tok /= '/'
if (.not.is_path) then
is_path = .false.
istart = ii
iend = ii
return
end if
istart = ii
do ii = min(iend + 1, nn), nn
tok = string(ii:ii)
select case(tok)
case('/')
exit
case default
iend = ii
cycle
end select
end do
end subroutine next
end function canon_path