File Paths in Co-array Fortran

Our first program will demonstrate file path operations in Co-array Fortran. Here’s the full source code:

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

This program demonstrates various file path operations in Co-array Fortran. Here’s a breakdown of the functionality:

  1. We use the join_path function to construct paths in a portable way.
  2. The split_path subroutine is used to split a path into its directory and base components.
  3. is_absolute_path checks whether a path is absolute.
  4. get_extension extracts the file extension from a filename.
  5. remove_extension removes the extension from a filename.
  6. relative_path finds a relative path between a base and a target.

To run the program, save it as file_paths.f90 and compile it using a Fortran compiler that supports Co-array Fortran:

$ gfortran -coarray=single file_paths.f90 -o file_paths
$ ./file_paths

This will output the results of various file path operations.

Note that Co-array Fortran doesn’t have built-in modules for file path manipulation like some other languages. The functions provided here are basic implementations and may not cover all edge cases or be as robust as dedicated libraries in other languages.