fortplot_directory_listing.f90 Source File


Source Code

module fortplot_directory_listing
    use fortplot_os_detection, only: is_windows
    implicit none
    private

    public :: list_directory_entries

contains

    subroutine list_directory_entries(path, entries, count, status)
        character(len=*), intent(in) :: path
        character(len=*), intent(out) :: entries(:)
        integer, intent(out) :: count
        integer, intent(out), optional :: status

        character(len=:), allocatable :: listing_file, command
        character(len=512) :: line
        logical :: ok
        integer :: unit_num, ios, local_status

        count = 0
        entries = ''
        local_status = 0

        if (len_trim(path) == 0) then
            local_status = -4
            goto 100
        end if

        if (index(path, '"') > 0) then
            local_status = -7
            goto 100
        end if

        listing_file = temp_listing_file()
        if (is_windows()) then
            command = 'cmd /c dir /b /a "' // trim(path) // '" > "' // trim(listing_file) // '"'
        else
            command = 'LC_ALL=C ls -1A "' // trim(path) // '" > "' // trim(listing_file) // '"'
        end if

        call run_listing_command(command, ok)
        if (.not. ok) then
            local_status = -1
            goto 100
        end if

        open(newunit=unit_num, file=trim(listing_file), status='old', action='read', iostat=ios)
        if (ios /= 0) then
            local_status = -1
            goto 100
        end if

        do
            read(unit_num, '(A)', iostat=ios) line
            if (ios /= 0) exit
            if (len_trim(line) == 0) cycle
            if (count >= size(entries)) then
                local_status = -6
                exit
            end if
            count = count + 1
            entries(count) = trim(line)
        end do
        close(unit_num)

100     continue
        if (allocated(listing_file)) then
            call delete_temp_file(listing_file)
        end if
        if (present(status)) status = local_status
    end subroutine list_directory_entries

    subroutine run_listing_command(command, ok)
        character(len=*), intent(in) :: command
        logical, intent(out) :: ok
        integer :: cmdstat, exitstat

        call execute_command_line(command, wait=.true., exitstat=exitstat, cmdstat=cmdstat)
        ok = (cmdstat == 0 .and. exitstat == 0)
    end subroutine run_listing_command

    function temp_listing_file() result(path)
        character(len=:), allocatable :: path
        integer :: count, rate, max_count

        call system_clock(count, rate, max_count)
        if (is_windows()) then
            path = 'fortplot_directory_listing_' // trim(int_to_str(count)) // '.txt'
        else
            path = '/tmp/fortplot_directory_listing_' // trim(int_to_str(count)) // '.txt'
        end if
    end function temp_listing_file

    subroutine delete_temp_file(path)
        character(len=*), intent(in) :: path
        integer :: unit_num, ios
        logical :: exists

        inquire(file=trim(path), exist=exists)
        if (.not. exists) return

        open(newunit=unit_num, file=trim(path), status='old', iostat=ios)
        if (ios == 0) close(unit_num, status='delete')
    end subroutine delete_temp_file

    function int_to_str(value) result(text)
        integer, intent(in) :: value
        character(len=32) :: text

        write(text, '(I0)') value
    end function int_to_str

end module fortplot_directory_listing