@@ -7,6 +7,8 @@ module fpm_filesystem
7
7
OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD
8
8
use fpm_environment, only: separator, get_env
9
9
use fpm_strings, only: f_string, replace, string_t, split
10
+ use iso_c_binding, only: c_int8_t, c_int16_t, c_int32_t, c_int64_t, c_int128_t, c_char, c_ptr, c_int, c_loc, c_long, c_short, &
11
+ c_null_char, c_associated, c_f_pointer
10
12
implicit none
11
13
private
12
14
public :: basename, canon_path, dirname, is_dir, join_path, number_of_rows, read_lines, list_files, env_variable, &
@@ -16,6 +18,143 @@ module fpm_filesystem
16
18
17
19
integer , parameter :: LINE_BUFFER_LEN = 1000
18
20
21
+ #if (defined(MINGW64))
22
+ type, bind(c) :: stat_t
23
+ integer (kind= c_int32_t) :: st_dev
24
+ integer (kind= c_int16_t) :: st_ino
25
+ integer (kind= c_int16_t) :: st_mode
26
+ integer (kind= c_int16_t) :: st_nlink
27
+
28
+ integer (kind= c_int16_t) :: st_uid
29
+ integer (kind= c_int16_t) :: st_gid
30
+
31
+ integer (kind= c_int32_t) :: st_rdev
32
+ integer (kind= c_int32_t) :: st_size
33
+
34
+ integer (kind= c_int64_t) :: st_atime
35
+ integer (kind= c_int64_t) :: st_mtime
36
+ integer (kind= c_int64_t) :: st_ctime
37
+ end type
38
+ #elif (defined(MINGW32))
39
+ type, bind(c) :: stat_t
40
+ integer (kind= c_int32_t) :: st_dev
41
+ integer (kind= c_int16_t) :: st_ino
42
+ integer (kind= c_int16_t) :: st_mode
43
+ integer (kind= c_int16_t) :: st_nlink
44
+
45
+ integer (kind= c_int16_t) :: st_uid
46
+ integer (kind= c_int16_t) :: st_gid
47
+
48
+ integer (kind= c_int32_t) :: st_rdev
49
+ integer (kind= c_int32_t) :: st_size
50
+
51
+ integer (kind= c_int32_t) :: st_atime
52
+ integer (kind= c_int32_t) :: st_mtime
53
+ integer (kind= c_int32_t) :: st_ctime
54
+ end type
55
+ #elif (defined(LINUX64))
56
+ type, bind(c) :: stat_t
57
+ integer (kind= c_int64_t) :: st_dev
58
+ integer (kind= c_int64_t) :: st_ino
59
+ integer (kind= c_int64_t) :: st_nlink
60
+ integer (kind= c_int32_t) :: st_mode
61
+
62
+ integer (kind= c_int32_t) :: st_uid
63
+ integer (kind= c_int32_t) :: st_gid
64
+ integer (kind= c_int32_t) :: pad0
65
+
66
+ integer (kind= c_int64_t) :: st_rdev
67
+ integer (kind= c_int64_t) :: st_size
68
+ integer (kind= c_int64_t) :: st_blksize
69
+ integer (kind= c_int64_t) :: st_blocks
70
+
71
+ integer (kind= c_int128_t) :: st_atime
72
+ integer (kind= c_int128_t) :: st_mtime
73
+ integer (kind= c_int128_t) :: st_ctime
74
+
75
+ integer (kind= c_int64_t) :: glibc_reserved4
76
+ integer (kind= c_int64_t) :: glibc_reserved5
77
+ integer (kind= c_int64_t) :: glibc_reserved6
78
+ end type
79
+ #elif (defined(LINUX32))
80
+ type, bind(c) :: stat_t
81
+ integer (kind= c_int64_t) :: st_dev
82
+ integer (kind= c_int16_t) :: pad1
83
+ integer (kind= c_int32_t) :: st_ino
84
+ integer (kind= c_int32_t) :: st_mode
85
+ integer (kind= c_int32_t) :: st_nlink
86
+
87
+ integer (kind= c_int32_t) :: st_uid
88
+ integer (kind= c_int32_t) :: st_gid
89
+ integer (kind= c_int64_t) :: st_rdev
90
+ integer (kind= c_int16_t) :: pad2
91
+
92
+ integer (kind= c_int32_t) :: st_size
93
+ integer (kind= c_int32_t) :: st_blksize
94
+ integer (kind= c_int32_t) :: st_blocks
95
+
96
+ integer (kind= c_int64_t) :: st_atime
97
+ integer (kind= c_int64_t) :: st_mtime
98
+ integer (kind= c_int64_t) :: st_ctime
99
+
100
+ integer (kind= c_int32_t) :: glibc_reserved4
101
+ integer (kind= c_int32_t) :: glibc_reserved5
102
+ end type
103
+ #endif
104
+
105
+ #if (defined(MINGW64) || defined(MINGW32))
106
+ type, bind(c) :: dirent
107
+ integer (kind= c_long) :: d_ino
108
+ integer (kind= c_short) :: d_reclen
109
+ integer (kind= c_short) :: d_namlen
110
+ character (len= 1 ,kind= c_char) :: d_name(260 )
111
+ end type
112
+ #elif (defined(LINUX64))
113
+ type, bind(c) :: dirent
114
+ integer (kind= c_int64_t) :: d_ino
115
+ integer (kind= c_int64_t) :: d_off
116
+ integer (kind= c_int16_t) :: d_reclen
117
+ integer (kind= c_int8_t) :: d_type
118
+ character (len= 1 ,kind= c_char) :: d_name(256 )
119
+ end type
120
+ #elif (defined(LINUX32))
121
+ type, bind(c) :: dirent
122
+ integer (kind= c_int32_t) :: d_ino
123
+ integer (kind= c_int32_t) :: d_off
124
+ integer (kind= c_int16_t) :: d_reclen
125
+ integer (kind= c_int8_t) :: d_type
126
+ character (len= 1 ,kind= c_char) :: d_name(256 )
127
+ end type
128
+ #endif
129
+
130
+ #if (defined(MINGW64) || defined(MINGW32) || defined(LINUX64) || defined(LINUX32))
131
+ interface
132
+ function c_stat (path , buf ) result(r) bind(c, name= " stat" )
133
+ import c_char, c_ptr, c_int
134
+ character (kind= c_char), intent (in ) :: path(* )
135
+ type (c_ptr), value :: buf
136
+ integer (kind= c_int) :: r
137
+ end function c_stat
138
+
139
+ function c_opendir (dir ) result(r) bind(c, name= " opendir" )
140
+ import c_char, c_ptr
141
+ character (kind= c_char), intent (in ) :: dir(* )
142
+ type (c_ptr) :: r
143
+ end function c_opendir
144
+
145
+ function c_readdir (dir ) result(r) bind(c, name= " readdir" )
146
+ import c_ptr
147
+ type (c_ptr), intent (in ), value :: dir
148
+ type (c_ptr) :: r
149
+ end function c_readdir
150
+
151
+ function c_closedir (dir ) result(r) bind(c, name= " closedir" )
152
+ import c_ptr, c_int
153
+ type (c_ptr), intent (in ), value :: dir
154
+ integer (kind= c_int) :: r
155
+ end function c_closedir
156
+ end interface
157
+ #endif
19
158
20
159
contains
21
160
@@ -312,6 +451,107 @@ subroutine mkdir(dir)
312
451
end subroutine mkdir
313
452
314
453
454
+ #if (defined(MINGW64) || defined(MINGW32) || defined(LINUX64) || defined(LINUX32))
455
+ ! > Get file & directory names in directory `dir` using iso_c_binding.
456
+ ! !
457
+ ! ! - File/directory names return are relative to cwd, ie. preprended with `dir`
458
+ ! ! - Includes files starting with `.` except current directory and parent directory
459
+ ! !
460
+ recursive subroutine list_files (dir , files , recurse )
461
+ character (len=* ), intent (in ) :: dir
462
+ type (string_t), allocatable , intent (out ) :: files(:)
463
+ logical , intent (in ), optional :: recurse
464
+
465
+ integer :: i
466
+ type (string_t), allocatable :: dir_files(:)
467
+ type (string_t), allocatable :: sub_dir_files(:)
468
+
469
+ type (c_ptr) :: dir_handle
470
+ type (c_ptr) :: dir_entry_c
471
+ type (dirent), pointer :: dir_entry_fortran
472
+ character (len= :), allocatable :: string_fortran
473
+ integer , parameter :: N_MAX = 256
474
+ type (string_t) :: files_tmp(N_MAX)
475
+ integer (kind= c_int) :: r
476
+
477
+ if (.not. is_dir_c(dir(1 :len_trim (dir))// c_null_char)) then
478
+ allocate (files(0 ))
479
+ return
480
+ end if
481
+
482
+ dir_handle = c_opendir(dir(1 :len_trim (dir))// c_null_char)
483
+ if (.not. c_associated(dir_handle)) then
484
+ print * , ' c_opendir() failed'
485
+ error stop
486
+ end if
487
+
488
+ i = 0
489
+ allocate (files(0 ))
490
+
491
+ do
492
+ dir_entry_c = c_readdir(dir_handle)
493
+ if (.not. c_associated(dir_entry_c)) then
494
+ exit
495
+ else
496
+ call c_f_pointer(dir_entry_c, dir_entry_fortran)
497
+ string_fortran = f_string(dir_entry_fortran% d_name)
498
+
499
+ if ((string_fortran .eq. ' .' .or. string_fortran .eq. ' ..' )) then
500
+ cycle
501
+ end if
502
+
503
+ i = i + 1
504
+
505
+ if (i .gt. N_MAX) then
506
+ files = [files, files_tmp]
507
+ i = 1
508
+ end if
509
+
510
+ files_tmp(i)% s = join_path(dir, string_fortran)
511
+ end if
512
+ end do
513
+
514
+ r = c_closedir(dir_handle)
515
+
516
+ if (r .ne. 0 ) then
517
+ print * , ' c_closedir() failed'
518
+ error stop
519
+ end if
520
+
521
+ if (i .gt. 0 ) then
522
+ files = [files, files_tmp(1 :i)]
523
+ end if
524
+
525
+ if (present (recurse)) then
526
+ if (recurse) then
527
+
528
+ allocate (sub_dir_files(0 ))
529
+
530
+ do i= 1 ,size (files)
531
+ if (is_dir_c(files(i)% s// c_null_char)) then
532
+ call list_files(files(i)% s, dir_files, recurse= .true. )
533
+ sub_dir_files = [sub_dir_files, dir_files]
534
+ end if
535
+ end do
536
+
537
+ files = [files, sub_dir_files]
538
+ end if
539
+ end if
540
+ end subroutine list_files
541
+
542
+ function is_dir_c (path ) result(r)
543
+ character (kind= c_char), intent (in ) :: path(* )
544
+ logical :: r
545
+ type (stat_t), target :: buf
546
+ integer (kind= c_int) :: exists
547
+ integer (kind= c_int), parameter :: S_IFMT = 61440
548
+ integer (kind= c_int), parameter :: S_IFDIR = 16384
549
+
550
+ exists = c_stat(path, c_loc(buf))
551
+ r = exists .eq. 0 .and. iand (int (buf% st_mode, kind= c_int), S_IFMT) .eq. S_IFDIR
552
+ end function is_dir_c
553
+
554
+ #else
315
555
! > Get file & directory names in directory `dir`.
316
556
! !
317
557
! ! - File/directory names return are relative to cwd, ie. preprended with `dir`
@@ -376,7 +616,7 @@ recursive subroutine list_files(dir, files, recurse)
376
616
end if
377
617
378
618
end subroutine list_files
379
-
619
+ # endif
380
620
381
621
! > test if pathname already exists
382
622
logical function exists (filename ) result(r)
0 commit comments