File System Directories

The Fortran language standard does not feature intrinsic routines for direct file system directory access, like reading the contents of a directory. On FreeBSD and Linux, the fortran-unix library can be included that contains ISO C binding interfaces to the POSIX functions opendir(), readdir(), and closedir().

fortran-unix

Clone the fortran-unix repository and build the static library libfortran-unix.a:

$ git clone https://github.com/interkosmos/fortran-unix
$ cd fortran-unix/
$ make

Import the module unix and link your Fortran application with libfortran-unix.a. To link the library, point the include search path parameter -I to the directory containing the module files (*.mod).

Example

In the example program, the wrapper function c_readdir() returns the derived type c_dirent, containing the entry name d_name. The C character array must be converted to Fortran string first, using the utility routine c_f_str_chars(). A trailing / is appended to the output if the entry is a directory itself (type DT_DIR).

! example.f90
program main
    use, intrinsic :: iso_c_binding
    use :: unix
    implicit none
    character(len=*), parameter :: PATH = '/'
    character(len=256)          :: entry_name
    type(c_dirent), pointer     :: dirent_ptr
    type(c_ptr)                 :: dir_ptr
    integer                     :: rc

    ! Open directory.
    dir_ptr = c_opendir(PATH // c_null_char)

    if (.not. c_associated(dir_ptr)) then
        call c_perror('opendir()' // c_null_char)
        stop
    end if

    print '("Contents of directory ", a, ":")', PATH

    ! Read in directory entries and output file names.
    do
        ! Get next directory entry.
        dirent_ptr => f_readdir(dir_ptr)

        ! Exit if pointer is null.
        if (.not. associated(dirent_ptr)) exit

        ! Convert C char array to Fortran string.
        call c_f_str_chars(dirent_ptr%d_name, entry_name)

        select case (dirent_ptr%d_type)
            case (DT_DIR)
                ! Entry is directory.
                print '(2a)', trim(entry_name), '/'
            case default
                ! Entry is file.
                print '(a)', trim(entry_name)
        end select
    end do

    ! Close directory.
    rc = c_closedir(dir_ptr)
end program main

We compile the module and the example program with GNU Fortran, and then run the binary to print out the contents of root directory / (unsorted).

$ gfortran10 -I./fortran-unix/ -o example example.f90 libfortran-unix.a
$ ./example
Contents of directory /:
./
../
entropy
dev/
var/
sbin/
home
mnt/
tmp/
sys
libexec/
COPYRIGHT
media/
lib/
rescue/
proc/
root/
zroot/
usr/
bin/
net/
boot/
etc/

References