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