Skip to content

Commit a82a071

Browse files
committed
Add: path canonicalizer for path comparison
Returns canonical path form with redundant artifacts.
1 parent 0fde601 commit a82a071

File tree

1 file changed

+90
-1
lines changed

1 file changed

+90
-1
lines changed

fpm/src/fpm_filesystem.f90

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module fpm_filesystem
55
use fpm_strings, only: f_string, string_t, split
66
implicit none
77
private
8-
public :: basename, dirname, is_dir, join_path, number_of_rows, read_lines, list_files,&
8+
public :: basename, canon_path, dirname, is_dir, join_path, number_of_rows, read_lines, list_files,&
99
mkdir, exists, get_temp_filename, windows_path
1010

1111
integer, parameter :: LINE_BUFFER_LEN = 1000
@@ -40,6 +40,76 @@ function basename(path,suffix) result (base)
4040
end function basename
4141

4242

43+
function canon_path(path) result(canon)
44+
! Canonicalize path for comparison
45+
! Handles path string redundancies
46+
! Does not test existence of path
47+
!
48+
! To be replaced by realpath/_fullname in stdlib_os
49+
!
50+
character(*), intent(in) :: path
51+
character(:), allocatable :: canon
52+
53+
integer :: i, j
54+
integer :: iback
55+
character(len(path)) :: nixpath
56+
character(len(path)) :: temp
57+
58+
nixpath = unix_path(path)
59+
60+
j = 1
61+
do i=1,len(nixpath)
62+
63+
! Skip back to last directory for '/../'
64+
if (i > 4) then
65+
66+
if (nixpath(i-3:i) == '/../') then
67+
68+
iback = scan(nixpath(1:i-4),'/',back=.true.)
69+
if (iback > 0) then
70+
j = iback + 1
71+
cycle
72+
end if
73+
74+
end if
75+
76+
end if
77+
78+
if (i > 1 .and. j > 1) then
79+
80+
! Ignore current directory reference
81+
if (nixpath(i-1:i) == './') then
82+
83+
j = j - 1
84+
cycle
85+
86+
end if
87+
88+
! Ignore repeated separators
89+
if (nixpath(i-1:i) == '//') then
90+
91+
cycle
92+
93+
end if
94+
95+
! Do NOT include trailing slash
96+
if (i == len(nixpath) .and. nixpath(i:i) == '/') then
97+
cycle
98+
end if
99+
100+
end if
101+
102+
103+
temp(j:j) = nixpath(i:i)
104+
j = j + 1
105+
106+
end do
107+
108+
canon = temp(1:j-1)
109+
110+
end function canon_path
111+
112+
43113
function dirname(path) result (dir)
44114
! Extract dirname from path
45115
!
@@ -287,4 +357,23 @@ function windows_path(path) result(winpath)
287357

288358
end function windows_path
289359

360+
361+
function unix_path(path) result(nixpath)
362+
! Replace file system separators for unix
363+
!
364+
character(*), intent(in) :: path
365+
character(:), allocatable :: nixpath
366+
367+
integer :: idx
368+
369+
nixpath = path
370+
371+
idx = index(nixpath,'\')
372+
do while(idx > 0)
373+
nixpath(idx:idx) = '/'
374+
idx = index(nixpath,'\')
375+
end do
376+
377+
end function unix_path
378+
290379
end module fpm_filesystem

0 commit comments

Comments
 (0)