Skip to content

Commit 0c8e137

Browse files
committed
Hack around the canon_path function bug
1 parent bef08cc commit 0c8e137

File tree

1 file changed

+73
-42
lines changed

1 file changed

+73
-42
lines changed

fpm/src/fpm_filesystem.f90

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -80,67 +80,98 @@ end function basename
8080
!!
8181
!! To be replaced by realpath/_fullname in stdlib_os
8282
!!
83-
function canon_path(path) result(canon)
84-
character(*), intent(in) :: path
85-
character(:), allocatable :: canon
83+
!! FIXME: Lot's of ugly hacks following here
84+
function canon_path(path)
85+
character(len=*), intent(in) :: path
86+
character(len=:), allocatable :: canon_path
87+
character(len=:), allocatable :: nixpath
8688

87-
integer :: i, j
88-
integer :: iback
89-
character(len(path)) :: nixpath
90-
character(len(path)) :: temp
89+
integer :: ii, istart, iend, stat, nn, last
90+
logical :: is_path, absolute
9191

9292
nixpath = unix_path(path)
9393

94-
j = 1
95-
do i=1,len(nixpath)
96-
97-
! Skip back to last directory for '/../'
98-
if (i > 4) then
99-
100-
if (nixpath(i-3:i) == '/../') then
94+
istart = 0
95+
nn = 0
96+
iend = 0
97+
absolute = nixpath(1:1) == "/"
98+
if (absolute) then
99+
canon_path = "/"
100+
else
101+
canon_path = ""
102+
end if
101103

102-
iback = scan(nixpath(1:i-4),'/',back=.true.)
103-
if (iback > 0) then
104-
j = iback + 1
105-
cycle
104+
do while(iend < len(nixpath))
105+
call next(nixpath, istart, iend, is_path)
106+
if (is_path) then
107+
select case(nixpath(istart:iend))
108+
case(".", "") ! always drop empty paths
109+
case("..")
110+
if (nn > 0) then
111+
last = scan(canon_path(:len(canon_path)-1), "/", back=.true.)
112+
canon_path = canon_path(:last)
113+
nn = nn - 1
114+
else
115+
if (.not. absolute) then
116+
canon_path = canon_path // nixpath(istart:iend) // "/"
117+
end if
106118
end if
107-
108-
end if
109-
119+
case default
120+
nn = nn + 1
121+
canon_path = canon_path // nixpath(istart:iend) // "/"
122+
end select
110123
end if
124+
end do
111125

112-
if (i > 1 .and. j > 1) then
113-
114-
! Ignore current directory reference
115-
if (nixpath(i-1:i) == './') then
116-
117-
j = j - 1
118-
cycle
119-
120-
end if
126+
if (len(canon_path) == 0) canon_path = "."
127+
if (len(canon_path) > 1 .and. canon_path(len(canon_path):) == "/") then
128+
canon_path = canon_path(:len(canon_path)-1)
129+
end if
121130

122-
! Ignore repeated separators
123-
if (nixpath(i-1:i) == '//') then
131+
contains
124132

125-
cycle
133+
subroutine next(string, istart, iend, is_path)
134+
character(len=*), intent(in) :: string
135+
integer, intent(inout) :: istart
136+
integer, intent(inout) :: iend
137+
logical, intent(inout) :: is_path
126138

127-
end if
139+
integer :: ii, nn
140+
character :: tok, last
128141

129-
! Do NOT include trailing slash
130-
if (i == len(nixpath) .and. nixpath(i:i) == '/') then
131-
cycle
132-
end if
142+
nn = len(string)
133143

144+
if (iend >= nn) then
145+
istart = nn
146+
iend = nn
147+
return
134148
end if
135149

150+
ii = min(iend + 1, nn)
151+
tok = string(ii:ii)
136152

137-
temp(j:j) = nixpath(i:i)
138-
j = j + 1
153+
is_path = tok /= '/'
139154

140-
end do
155+
if (.not.is_path) then
156+
is_path = .false.
157+
istart = ii
158+
iend = ii
159+
return
160+
end if
141161

142-
canon = temp(1:j-1)
162+
istart = ii
163+
do ii = min(iend + 1, nn), nn
164+
tok = string(ii:ii)
165+
select case(tok)
166+
case('/')
167+
exit
168+
case default
169+
iend = ii
170+
cycle
171+
end select
172+
end do
143173

174+
end subroutine next
144175
end function canon_path
145176

146177

0 commit comments

Comments
 (0)