program file_paths
use, intrinsic :: iso_fortran_env
implicit none
character(len=:), allocatable :: path, dir, base, ext, filename
logical :: is_absolute
integer :: status
! Join path components
path = join_path(['dir1', 'dir2', 'filename'])
print *, 'path:', path
! Normalize paths
print *, join_path(['dir1//', 'filename'])
print *, join_path(['dir1/../dir1', 'filename'])
! Split path into directory and base
call split_path(path, dir, base)
print *, 'Dir(path):', dir
print *, 'Base(path):', base
! Check if path is absolute
is_absolute = is_absolute_path('dir/file')
print *, is_absolute
is_absolute = is_absolute_path('/dir/file')
print *, is_absolute
! Get file extension
filename = 'config.json'
ext = get_extension(filename)
print *, ext
! Remove extension from filename
print *, remove_extension(filename)
! Find relative path
print *, relative_path('a/b', 'a/b/t/file')
print *, relative_path('a/b', 'a/c/t/file')
contains
function join_path(components) result(path)
character(len=*), dimension(:), intent(in) :: components
character(len=:), allocatable :: path
integer :: i
path = trim(components(1))
do i = 2, size(components)
path = trim(path) // '/' // trim(components(i))
end do
end function join_path
subroutine split_path(path, dir, base)
character(len=*), intent(in) :: path
character(len=:), allocatable, intent(out) :: dir, base
integer :: last_sep
last_sep = index(path, '/', back=.true.)
if (last_sep > 0) then
dir = path(:last_sep-1)
base = path(last_sep+1:)
else
dir = ''
base = path
end if
end subroutine split_path
function is_absolute_path(path) result(is_absolute)
character(len=*), intent(in) :: path
logical :: is_absolute
is_absolute = (len(path) > 0 .and. path(1:1) == '/')
end function is_absolute_path
function get_extension(filename) result(ext)
character(len=*), intent(in) :: filename
character(len=:), allocatable :: ext
integer :: dot_pos
dot_pos = index(filename, '.', back=.true.)
if (dot_pos > 0) then
ext = filename(dot_pos:)
else
ext = ''
end if
end function get_extension
function remove_extension(filename) result(name_without_ext)
character(len=*), intent(in) :: filename
character(len=:), allocatable :: name_without_ext
integer :: dot_pos
dot_pos = index(filename, '.', back=.true.)
if (dot_pos > 0) then
name_without_ext = filename(:dot_pos-1)
else
name_without_ext = filename
end if
end function remove_extension
function relative_path(base, target) result(rel_path)
character(len=*), intent(in) :: base, target
character(len=:), allocatable :: rel_path
integer :: i, common_prefix_len
common_prefix_len = 0
do i = 1, min(len(base), len(target))
if (base(i:i) /= target(i:i)) exit
if (base(i:i) == '/') common_prefix_len = i
end do
if (common_prefix_len == 0) then
rel_path = target
else
rel_path = repeat('../', count(base(common_prefix_len+1:) == '/')) // &
target(common_prefix_len+2:)
end if
end function relative_path
end program file_paths