@@ -80,67 +80,98 @@ end function basename
80
80
! !
81
81
! ! To be replaced by realpath/_fullname in stdlib_os
82
82
! !
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
86
88
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
91
91
92
92
nixpath = unix_path(path)
93
93
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
101
103
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
106
118
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
110
123
end if
124
+ end do
111
125
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
121
130
122
- ! Ignore repeated separators
123
- if (nixpath(i-1 :i) == ' //' ) then
131
+ contains
124
132
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
126
138
127
- end if
139
+ integer :: ii, nn
140
+ character :: tok, last
128
141
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)
133
143
144
+ if (iend >= nn) then
145
+ istart = nn
146
+ iend = nn
147
+ return
134
148
end if
135
149
150
+ ii = min (iend + 1 , nn)
151
+ tok = string (ii:ii)
136
152
137
- temp(j:j) = nixpath(i:i)
138
- j = j + 1
153
+ is_path = tok /= ' /'
139
154
140
- end do
155
+ if (.not. is_path) then
156
+ is_path = .false.
157
+ istart = ii
158
+ iend = ii
159
+ return
160
+ end if
141
161
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
143
173
174
+ end subroutine next
144
175
end function canon_path
145
176
146
177
0 commit comments