Skip to content

Commit 029860f

Browse files
authored
Merge branch 'master' into exists
2 parents 39ab1b7 + a8519b6 commit 029860f

File tree

6 files changed

+317
-24
lines changed

6 files changed

+317
-24
lines changed

doc/specs/stdlib_system.md

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,80 @@ Subroutine
726726

727727
---
728728

729+
## `get_cwd` - Gets the current working directory
730+
731+
### Status
732+
733+
Experimental
734+
735+
### Description
736+
737+
This subroutine retrieves the current working directory the running process is executing from.
738+
It is designed to work across multiple platforms. On Windows, paths with both forward `/` and backward `\` slashes are accepted.
739+
740+
### Syntax
741+
742+
`call [[stdlib_system(module):get_cwd(subroutine)]] (cwd [, err])`
743+
744+
### Class
745+
746+
Subroutine
747+
748+
### Arguments
749+
750+
`cwd`: Shall be a character string for receiving the path of the current working directory (cwd). It is an `intent(out)` argument.
751+
752+
`err`(optional): Shall be of type `state_type`, and is used for error handling. It is an `intent(out)` argument.
753+
754+
### Return values
755+
756+
`err` is an optional state return flag. On error if not requested, an `FS_ERROR` will trigger an error stop.
757+
758+
### Example
759+
760+
```fortran
761+
{!example/system/example_cwd.f90!}
762+
```
763+
764+
---
765+
766+
## `set_cwd` - Sets the current working directory
767+
768+
### Status
769+
770+
Experimental
771+
772+
### Description
773+
774+
This subrotine sets the current working directory the process is executing from.
775+
It is designed to work across multiple platforms. On Windows, paths with both forward `/` and backward `\` slashes are accepted.
776+
777+
### Syntax
778+
779+
`call [[stdlib_system(module):set_cwd(subroutine)]] (path [, err])`
780+
781+
### Class
782+
783+
Subroutine
784+
785+
### Arguments
786+
787+
`path`: Shall be a character string containing the path of the directory. It is an `intent(in)` argument.
788+
789+
`err`(optional): Shall be of type `state_type`, and is used for error handling. It is an `intent(out)` argument.
790+
791+
### Return values
792+
793+
`err` is an optional state return flag. On error if not requested, an `FS_ERROR` will trigger an error stop.
794+
795+
### Example
796+
797+
```fortran
798+
{!example/system/example_cwd.f90!}
799+
```
800+
801+
---
802+
729803
## `exists` - Checks if a path exists in the filesystem
730804

731805
### Status
@@ -768,8 +842,6 @@ Function
768842

769843
`err`(optional): It is an optional state return flag. If not requested and an error occurs, an `FS_ERROR` will trigger an error stop.
770844

771-
### Example
772-
773845
```fortran
774846
{!example/system/example_exists.f90!}
775847
```
@@ -812,6 +884,8 @@ None.
812884
{!example/system/example_null_device.f90!}
813885
```
814886

887+
---
888+
815889
## `delete_file` - Delete a file
816890

817891
### Status
@@ -853,6 +927,8 @@ The file is removed from the filesystem if the operation is successful. If the o
853927
{!example/system/example_delete_file.f90!}
854928
```
855929

930+
---
931+
856932
## `join_path` - Joins the provided paths according to the OS
857933

858934
### Status
@@ -915,6 +991,8 @@ The result is an `allocatable` character string or `type(string_type)`
915991
{!example/system/example_path_join.f90!}
916992
```
917993

994+
---
995+
918996
## `split_path` - splits a path immediately following the last separator
919997

920998
### Status
@@ -955,6 +1033,8 @@ The splitted path. `head` and `tail`.
9551033
{!example/system/example_path_split_path.f90!}
9561034
```
9571035

1036+
---
1037+
9581038
## `base_name` - The last part of a path
9591039

9601040
### Status
@@ -990,6 +1070,8 @@ A character string or `type(string_type)`.
9901070
{!example/system/example_path_base_name.f90!}
9911071
```
9921072

1073+
---
1074+
9931075
## `dir_name` - Everything except the last part of the path
9941076

9951077
### Status

example/system/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ ADD_EXAMPLE(path_base_name)
1717
ADD_EXAMPLE(path_dir_name)
1818
ADD_EXAMPLE(make_directory)
1919
ADD_EXAMPLE(remove_directory)
20+
ADD_EXAMPLE(cwd)
2021
ADD_EXAMPLE(exists)
2122
ADD_EXAMPLE(is_regular_file)
2223
ADD_EXAMPLE(is_directory)
23-
ADD_EXAMPLE(is_symlink)
24+
ADD_EXAMPLE(is_symlink)

example/system/example_cwd.f90

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
! Illustrate the usage of `get_cwd`, `set_cwd`
2+
program example_cwd
3+
use stdlib_system, only: get_cwd, set_cwd
4+
use stdlib_error, only: state_type
5+
implicit none
6+
7+
character(len=:), allocatable :: path
8+
type(state_type) :: err
9+
10+
call get_cwd(path, err)
11+
12+
if (err%error()) then
13+
print *, "Error getting current working directory: "//err%print()
14+
end if
15+
16+
print *, "CWD: "//path
17+
18+
call set_cwd("./src", err)
19+
20+
if (err%error()) then
21+
print *, "Error setting current working directory: "//err%print()
22+
end if
23+
24+
call get_cwd(path, err)
25+
26+
if (err%error()) then
27+
print *, "Error getting current working directory after using set_cwd: "//err%print()
28+
end if
29+
30+
print *, "CWD: "//path
31+
end program example_cwd
32+

src/stdlib_system.F90

Lines changed: 99 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module stdlib_system
22
use, intrinsic :: iso_c_binding, only : c_int, c_long, c_ptr, c_null_ptr, c_int64_t, c_size_t, &
33
c_f_pointer
44
use stdlib_kinds, only: int64, dp, c_bool, c_char
5-
use stdlib_strings, only: to_c_char, find
5+
use stdlib_strings, only: to_c_char, find, to_string
66
use stdlib_string_type, only: string_type
77
use stdlib_optval, only: optval
88
use stdlib_error, only: state_type, STDLIB_SUCCESS, STDLIB_FS_ERROR
@@ -159,6 +159,32 @@ module stdlib_system
159159
!!
160160
public :: remove_directory
161161

162+
!! version: experimental
163+
!!
164+
!! Gets the current working directory of the process
165+
!! ([Specification](../page/specs/stdlib_system.html#get_cwd))
166+
!!
167+
!! ### Summary
168+
!! Gets the current working directory.
169+
!!
170+
!! ### Description
171+
!! This subroutine gets the current working directory the process is executing from.
172+
!!
173+
public :: get_cwd
174+
175+
!! version: experimental
176+
!!
177+
!! Sets the current working directory of the process
178+
!! ([Specification](../page/specs/stdlib_system.html#set_cwd))
179+
!!
180+
!! ### Summary
181+
!! Changes the current working directory to the one specified.
182+
!!
183+
!! ### Description
184+
!! This subroutine sets the current working directory the process is executing from.
185+
!!
186+
public :: set_cwd
187+
162188
!! version: experimental
163189
!!
164190
!! Deletes a specified file from the filesystem.
@@ -971,6 +997,25 @@ end function stdlib_is_directory
971997

972998
end function is_directory
973999

1000+
! A Helper function to convert C character arrays to Fortran character strings
1001+
function to_f_char(c_str_ptr, len) result(f_str)
1002+
type(c_ptr), intent(in) :: c_str_ptr
1003+
! length of the string excluding the null character
1004+
integer(kind=c_size_t), intent(in) :: len
1005+
character(:), allocatable :: f_str
1006+
1007+
integer :: i
1008+
character(kind=c_char), pointer :: c_str(:)
1009+
1010+
call c_f_pointer(c_str_ptr, c_str, [len])
1011+
1012+
allocate(character(len=len) :: f_str)
1013+
1014+
do concurrent (i=1:len)
1015+
f_str(i:i) = c_str(i)
1016+
end do
1017+
end function to_f_char
1018+
9741019
! A helper function to get the string describing an error from C functions.
9751020
! If `winapi` is false or not present, uses `strerror` provided by `<string.h>`
9761021
! Otherwise, uses `strerror` on unix and `FormatMessageA` on windows.
@@ -996,13 +1041,7 @@ end function strerror
9961041

9971042
c_str_ptr = strerror(len, winapi_)
9981043

999-
call c_f_pointer(c_str_ptr, c_str, [len])
1000-
1001-
allocate(character(len=len) :: str)
1002-
1003-
do concurrent (i=1:len)
1004-
str(i:i) = c_str(i)
1005-
end do
1044+
str = to_f_char(c_str_ptr, len)
10061045
end function c_get_strerror
10071046

10081047
!! makes an empty directory
@@ -1104,6 +1143,56 @@ end function stdlib_remove_directory
11041143

11051144
end subroutine remove_directory
11061145

1146+
subroutine get_cwd(cwd, err)
1147+
character(:), allocatable, intent(out) :: cwd
1148+
type(state_type), optional, intent(out) :: err
1149+
type(state_type) :: err0
1150+
1151+
interface
1152+
type(c_ptr) function stdlib_get_cwd(len, stat) bind(C, name='stdlib_get_cwd')
1153+
import c_ptr, c_size_t
1154+
integer(c_size_t), intent(out) :: len
1155+
integer :: stat
1156+
end function stdlib_get_cwd
1157+
end interface
1158+
1159+
type(c_ptr) :: c_str_ptr
1160+
integer(c_size_t) :: len
1161+
integer :: stat
1162+
1163+
c_str_ptr = stdlib_get_cwd(len, stat)
1164+
1165+
if (stat /= 0) then
1166+
err0 = FS_ERROR_CODE(stat, c_get_strerror())
1167+
call err0%handle(err)
1168+
end if
1169+
1170+
cwd = to_f_char(c_str_ptr, len)
1171+
1172+
end subroutine get_cwd
1173+
1174+
subroutine set_cwd(path, err)
1175+
character(len=*), intent(in) :: path
1176+
type(state_type), optional, intent(out) :: err
1177+
type(state_type) :: err0
1178+
1179+
interface
1180+
integer function stdlib_set_cwd(path) bind(C, name='stdlib_set_cwd')
1181+
import c_char
1182+
character(kind=c_char), intent(in) :: path(*)
1183+
end function stdlib_set_cwd
1184+
end interface
1185+
1186+
integer :: code
1187+
1188+
code = stdlib_set_cwd(to_c_char(trim(path)))
1189+
1190+
if (code /= 0) then
1191+
err0 = FS_ERROR_CODE(code, c_get_strerror())
1192+
call err0%handle(err)
1193+
end if
1194+
end subroutine set_cwd
1195+
11071196
!> Returns the file path of the null device for the current operating system.
11081197
!>
11091198
!> Version: Helper function.
@@ -1122,21 +1211,13 @@ end function process_null_device
11221211

11231212
end interface
11241213

1125-
integer(c_size_t) :: i, len
1214+
integer(c_size_t) :: len
11261215
type(c_ptr) :: c_path_ptr
1127-
character(kind=c_char), pointer :: c_path(:)
11281216

11291217
! Call the C function to get the null device path and its length
11301218
c_path_ptr = process_null_device(len)
1131-
call c_f_pointer(c_path_ptr,c_path,[len])
11321219

1133-
! Allocate the Fortran string with the length returned from C
1134-
allocate(character(len=len) :: path)
1135-
1136-
do concurrent (i=1:len)
1137-
path(i:i) = c_path(i)
1138-
end do
1139-
1220+
path = to_f_char(c_path_ptr, len)
11401221
end function null_device
11411222

11421223
!> Delete a file at the given path.

0 commit comments

Comments
 (0)