@@ -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
144175end function canon_path
145176
146177
0 commit comments