From 8d00eea4291202f0f01bd67daef95aedb973e44b Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Wed, 2 Jul 2025 03:17:01 +0530 Subject: [PATCH 01/10] added functions and relevant wrappers --- src/CMakeLists.txt | 5 +- src/stdlib_system.F90 | 124 +++++++++++++++++++++++++++++++++++++++++- src/stdlib_system.c | 46 ++++++++++++++++ 3 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 src/stdlib_system.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3cd99120..24fd9c56b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,14 +32,14 @@ set(fppFiles stdlib_linalg_kronecker.fypp stdlib_linalg_cross_product.fypp stdlib_linalg_eigenvalues.fypp - stdlib_linalg_solve.fypp + stdlib_linalg_solve.fypp stdlib_linalg_determinant.fypp stdlib_linalg_qr.fypp stdlib_linalg_inverse.fypp stdlib_linalg_pinv.fypp stdlib_linalg_norms.fypp stdlib_linalg_state.fypp - stdlib_linalg_svd.fypp + stdlib_linalg_svd.fypp stdlib_linalg_cholesky.fypp stdlib_linalg_schur.fypp stdlib_optval.fypp @@ -116,6 +116,7 @@ set(SRC stdlib_sorting_radix_sort.f90 stdlib_system_subprocess.c stdlib_system_subprocess.F90 + stdlib_system.c stdlib_system.F90 stdlib_sparse.f90 stdlib_specialfunctions_legendre.f90 diff --git a/src/stdlib_system.F90 b/src/stdlib_system.F90 index a9c3e4d55..dd83f4bbb 100644 --- a/src/stdlib_system.F90 +++ b/src/stdlib_system.F90 @@ -2,7 +2,7 @@ module stdlib_system use, intrinsic :: iso_c_binding, only : c_int, c_long, c_ptr, c_null_ptr, c_int64_t, c_size_t, & c_f_pointer use stdlib_kinds, only: int64, dp, c_bool, c_char -use stdlib_strings, only: to_c_char +use stdlib_strings, only: to_c_char, to_string use stdlib_error, only: state_type, STDLIB_SUCCESS, STDLIB_FS_ERROR implicit none private @@ -100,6 +100,36 @@ module stdlib_system !! public :: is_directory +!! version: experimental +!! +!! Makes an empty directory. +!! ([Specification](../page/specs/stdlib_system.html#make_directory)) +!! +!! ### Summary +!! Creates an empty directory with particular permissions. +!! +!! ### Description +!! This function makes an empty directory according to the path provided. +!! Relative paths as well as on Windows paths involving either `/` or `\` are accepted +!! appropriate error message is returned whenever any error occur. +!! +public :: make_directory + +!! version: experimental +!! +!! Removes an empty directory. +!! ([Specification](../page/specs/stdlib_system.html#remove_directory)) +!! +!! ### Summary +!! Deletes an empty directory. +!! +!! ### Description +!! This function deletes an empty directory according to the path provided. +!! Relative paths as well as on Windows paths involving either `/` or `\` are accepted. +!! appropriate error message is returned whenever any error occur. +!! +public :: remove_directory + !! version: experimental !! !! Deletes a specified file from the filesystem. @@ -690,6 +720,98 @@ end function stdlib_is_directory end function is_directory +function c_get_strerror() result(str) + character(len=:), allocatable :: str + + interface + type(c_ptr) function strerror(len) bind(C, name='stdlib_strerror') + import c_size_t, c_ptr, c_int + implicit none + integer(c_size_t), intent(out) :: len + end function strerror + end interface + + type(c_ptr) :: c_str_ptr + integer(c_size_t) :: len, i + character(kind=c_char), pointer :: c_str(:) + + c_str_ptr = strerror(len) + + call c_f_pointer(c_str_ptr, c_str, [len]) + + allocate(character(len=len) :: str) + + do concurrent (i=1:len) + str(i:i) = c_str(i) + end do +end function c_get_strerror + +!! makes an empty directory +subroutine make_directory(path, mode, err) + character(len=*), intent(in) :: path + integer, intent(in), optional :: mode + character, allocatable :: err_msg + type(state_type), optional, intent(out) :: err + + integer :: code + type(state_type) :: err0 + + + interface + integer function stdlib_make_directory(cpath, cmode) bind(C, name='stdlib_make_directory') + import c_char + character(kind=c_char), intent(in) :: cpath(*) + integer, intent(in) :: cmode + end function stdlib_make_directory + end interface + + if (is_windows() .and. present(mode)) then + ! _mkdir() doesn't have a `mode` argument + err0 = state_type(STDLIB_FS_ERROR, "mode argument not present for Windows") + call err0%handle(err) + return + end if + + code = stdlib_make_directory(to_c_char(trim(path)), mode) + + select case (code) + case (0) + return + case default + ! error + err0 = state_type(STDLIB_FS_ERROR, "code:", to_string(code)//',', c_get_strerror()) + call err0%handle(err) + end select +end subroutine make_directory + +!! Removes an empty directory +subroutine remove_directory(path, err) + character(len=*), intent(in) :: path + character, allocatable :: err_msg + type(state_type), optional, intent(out) :: err + + integer :: code + type(state_type) :: err0 + + interface + integer function stdlib_remove_directory(cpath) bind(C, name='stdlib_remove_directory') + import c_char + character(kind=c_char), intent(in) :: cpath(*) + end function stdlib_remove_directory + end interface + + code = stdlib_remove_directory(to_c_char(trim(path))) + + select case (code) + case (0) + return + case default + ! error + err0 = state_type(STDLIB_FS_ERROR, "code:", to_string(code)//',', c_get_strerror()) + call err0%handle(err) + end select +end subroutine remove_directory + !> Returns the file path of the null device for the current operating system. !> !> Version: Helper function. diff --git a/src/stdlib_system.c b/src/stdlib_system.c new file mode 100644 index 000000000..2d9368cc3 --- /dev/null +++ b/src/stdlib_system.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif /* ifdef _WIN32 */ + +char* stdlib_strerror(size_t* len){ + char* err = strerror(errno); + *len = strlen(err); + return err; +} + +int stdlib_make_directory(const char* path, mode_t mode){ + int code; +#ifdef _WIN32 + code = _mkdir(path); +#else + code = mkdir(path, mode); +#endif /* ifdef _WIN32 */ + + if (!code){ + return 0; + } + + return errno; +} + +int stdlib_remove_directory(const char* path){ + int code; +#ifdef _WIN32 + code = _rmdir(path); +#else + code = rmdir(path); +#endif /* ifdef _WIN32 */ + + if (!code){ + return 0; + } + + return errno; +} From c9345c1e1378e9d695f803442e1d2ccd9b223610 Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Wed, 2 Jul 2025 03:17:20 +0530 Subject: [PATCH 02/10] added tests --- test/system/test_filesystem.f90 | 80 ++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/test/system/test_filesystem.f90 b/test/system/test_filesystem.f90 index 4cf1690e4..0f5e24ea1 100644 --- a/test/system/test_filesystem.f90 +++ b/test/system/test_filesystem.f90 @@ -1,6 +1,6 @@ module test_filesystem use testdrive, only : new_unittest, unittest_type, error_type, check, skip_test - use stdlib_system, only: is_directory, delete_file + use stdlib_system, only: is_directory, delete_file, make_directory, remove_directory use stdlib_error, only: state_type implicit none @@ -17,7 +17,11 @@ subroutine collect_suite(testsuite) new_unittest("fs_is_directory_file", test_is_directory_file), & new_unittest("fs_delete_non_existent", test_delete_file_non_existent), & new_unittest("fs_delete_existing_file", test_delete_file_existing), & - new_unittest("fs_delete_file_being_dir", test_delete_directory) & + new_unittest("fs_delete_file_being_dir", test_delete_directory), & + new_unittest("fs_make_dir", test_make_directory), & + new_unittest("fs_make_dir_existing_dir", test_make_directory_existing), & + new_unittest("fs_remove_dir", test_remove_directory), & + new_unittest("fs_remove_dir_non_existent", test_remove_directory_nonexistent) & ] end subroutine collect_suite @@ -145,7 +149,79 @@ subroutine test_delete_directory(error) if (allocated(error)) return end subroutine test_delete_directory + + subroutine test_make_directory(error) + type(error_type), allocatable, intent(out) :: error + type(state_type) :: err + character(len=256) :: filename + integer :: ios,iocmd + character(len=512) :: msg + + filename = "test_directory" + call make_directory(filename, err=err) + call check(error, err%ok(), 'Could not make directory: '//err%print()) + if (allocated(error)) return + + ! Clean up: remove the empty directory + call execute_command_line('rmdir ' // filename, exitstat=ios, cmdstat=iocmd, cmdmsg=msg) + call check(error, ios==0 .and. iocmd==0, 'Cannot cleanup make_directory test: '//trim(msg)) + if (allocated(error)) return + end subroutine test_make_directory + + subroutine test_make_directory_existing(error) + type(error_type), allocatable, intent(out) :: error + type(state_type) :: err + character(len=256) :: filename + integer :: ios,iocmd + character(len=512) :: msg + + filename = "test_directory" + + call execute_command_line('mkdir ' // filename, exitstat=ios, cmdstat=iocmd, cmdmsg=msg) + call check(error, ios==0 .and. iocmd==0, 'Cannot init make_directory_existing test: '//trim(msg)) + if (allocated(error)) return + + call make_directory(filename, err=err) + call check(error, err%error(), 'Made an already existing directory somehow') + + ! Clean up: remove the empty directory + call execute_command_line('rmdir ' // filename, exitstat=ios, cmdstat=iocmd, cmdmsg=msg) + call check(error, ios==0 .and. iocmd==0, 'Cannot cleanup make_directory test: '//trim(msg)) + if (allocated(error)) return + end subroutine test_make_directory_existing + + subroutine test_remove_directory(error) + type(error_type), allocatable, intent(out) :: error + type(state_type) :: err + character(len=256) :: filename + integer :: ios,iocmd + character(len=512) :: msg + + filename = "test_directory" + + call execute_command_line('mkdir ' // filename, exitstat=ios, cmdstat=iocmd, cmdmsg=msg) + call check(error, ios==0 .and. iocmd==0, 'Cannot init remove_directory test: '//trim(msg)) + if (allocated(error)) return + + call remove_directory(filename, err) + call check(error, err%ok(), 'Could not remove directory: '//err%print()) + if (allocated(error)) then + ! Clean up: remove the empty directory + call execute_command_line('rmdir ' // filename, exitstat=ios, cmdstat=iocmd, cmdmsg=msg) + call check(error, ios==0 .and. iocmd==0, 'Cannot cleanup make_directory test: '//trim(msg)) + if (allocated(error)) return + end if + end subroutine test_remove_directory + + subroutine test_remove_directory_nonexistent(error) + type(error_type), allocatable, intent(out) :: error + type(state_type) :: err + + call remove_directory("random_name", err) + call check(error, err%error(), 'Somehow removed a non-existent directory!: ') + if (allocated(error)) return + end subroutine test_remove_directory_nonexistent end module test_filesystem From d94d7fb790e6bdfd431610e4befb19e7dfe1207c Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Wed, 2 Jul 2025 03:17:39 +0530 Subject: [PATCH 03/10] added specs --- doc/specs/stdlib_system.md | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/doc/specs/stdlib_system.md b/doc/specs/stdlib_system.md index 96eebb2e8..bb5b1afa2 100644 --- a/doc/specs/stdlib_system.md +++ b/doc/specs/stdlib_system.md @@ -456,6 +456,82 @@ The function returns a `logical` value: --- +## `make_directory` - Creates an empty directory + +### Status + +Experimental + +### Description + +It creates an empty directory. +It is designed to work across multiple platforms. On Windows, paths with both forward `/` and backward `\` slashes are accepted. + +### Syntax + +`call [[stdlib_system(module):make_directory(subroutine)]] (path, mode, err)` + +### Class + +Subroutine + +### Arguments + +`path`: Shall be a character string containing the path of the directory to create. It is an `intent(in)` argument. + +`mode`: Shall be a scalar integer indicating the permission bits required (Not applicable to Windows). It is an `optional, intent(in)` argument. + +`err`: Shall be of type `state_type`, for error handling. It is an `optional, intent(out)` argument. + +### Return values + +The `err` is set accordingly. + +### Example + +```fortran +{!example/system/example_make_directory.f90!} +``` + +--- + +## `remove_directory` - Removes an empty directory + +### Status + +Experimental + +### Description + +It deletes an empty directory. +It is designed to work across multiple platforms. On Windows, paths with both forward `/` and backward `\` slashes are accepted. + +### Syntax + +`call [[stdlib_system(module):remove_directory(subroutine)]] (path, err)` + +### Class + +Subroutine + +### Arguments + +`path`: Shall be a character string containing the path of the directory to create. It is an `intent(in)` argument. + +`err`: Shall be of type `state_type`, for error handling. It is an `intent(out)` argument. + +### Return values + +The `err` is set accordingly. + +### Example + +```fortran +{!example/system/example_remove_directory.f90!} +``` + +--- + ## `null_device` - Return the null device file path ### Status From e1f68d833d55b0fdd141f9e1a2861ec76310200c Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Wed, 2 Jul 2025 03:18:04 +0530 Subject: [PATCH 04/10] added examples --- example/system/CMakeLists.txt | 2 ++ example/system/example_make_directory.f90 | 17 +++++++++++++++++ example/system/example_remove_directory.f90 | 17 +++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 example/system/example_make_directory.f90 create mode 100644 example/system/example_remove_directory.f90 diff --git a/example/system/CMakeLists.txt b/example/system/CMakeLists.txt index a2a7525c9..8189d525b 100644 --- a/example/system/CMakeLists.txt +++ b/example/system/CMakeLists.txt @@ -11,3 +11,5 @@ ADD_EXAMPLE(process_5) ADD_EXAMPLE(process_6) ADD_EXAMPLE(process_7) ADD_EXAMPLE(sleep) +ADD_EXAMPLE(make_directory) +ADD_EXAMPLE(remove_directory) diff --git a/example/system/example_make_directory.f90 b/example/system/example_make_directory.f90 new file mode 100644 index 000000000..5e551b810 --- /dev/null +++ b/example/system/example_make_directory.f90 @@ -0,0 +1,17 @@ +! Illustrate the usage of make_directory +program example_make_directory + use stdlib_system, only: make_directory, is_directory + use stdlib_error, only: state_type + implicit none + + type(state_type) :: err + + call make_directory("test", err=err) + + if (err%error()) then + print *, err%print() + else + print *, "directory created sucessfully" + end if + +end program example_make_directory diff --git a/example/system/example_remove_directory.f90 b/example/system/example_remove_directory.f90 new file mode 100644 index 000000000..993adf4f9 --- /dev/null +++ b/example/system/example_remove_directory.f90 @@ -0,0 +1,17 @@ +! Illustrate the usage of remove_directory +program example_remove_directory + use stdlib_system, only: make_directory, is_directory, remove_directory + use stdlib_error, only: state_type + implicit none + + type(state_type) :: err + + call remove_directory("directory_to_be_removed", err) + + if (err%error()) then + print *, err%print() + else + print *, "directory removed successfully" + end if + +end program example_remove_directory From c3db3a65723cb3e5c45bc511d2e1ba0c567fc2d0 Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Wed, 2 Jul 2025 04:01:02 +0530 Subject: [PATCH 05/10] cleanup --- src/stdlib_system.F90 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/stdlib_system.F90 b/src/stdlib_system.F90 index dd83f4bbb..2e0d3a1aa 100644 --- a/src/stdlib_system.F90 +++ b/src/stdlib_system.F90 @@ -725,7 +725,7 @@ function c_get_strerror() result(str) interface type(c_ptr) function strerror(len) bind(C, name='stdlib_strerror') - import c_size_t, c_ptr, c_int + import c_size_t, c_ptr implicit none integer(c_size_t), intent(out) :: len end function strerror @@ -750,7 +750,6 @@ end function c_get_strerror subroutine make_directory(path, mode, err) character(len=*), intent(in) :: path integer, intent(in), optional :: mode - character, allocatable :: err_msg type(state_type), optional, intent(out) :: err integer :: code @@ -787,7 +786,6 @@ end subroutine make_directory !! Removes an empty directory subroutine remove_directory(path, err) character(len=*), intent(in) :: path - character, allocatable :: err_msg type(state_type), optional, intent(out) :: err integer :: code From 8012ac8d0dd03b2a31aff345e08a93399f1a06df Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Sat, 5 Jul 2025 21:08:49 +0530 Subject: [PATCH 06/10] improve test flow a bit --- test/system/test_filesystem.f90 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/system/test_filesystem.f90 b/test/system/test_filesystem.f90 index 0f5e24ea1..add6a9323 100644 --- a/test/system/test_filesystem.f90 +++ b/test/system/test_filesystem.f90 @@ -166,7 +166,6 @@ subroutine test_make_directory(error) ! Clean up: remove the empty directory call execute_command_line('rmdir ' // filename, exitstat=ios, cmdstat=iocmd, cmdmsg=msg) call check(error, ios==0 .and. iocmd==0, 'Cannot cleanup make_directory test: '//trim(msg)) - if (allocated(error)) return end subroutine test_make_directory subroutine test_make_directory_existing(error) @@ -187,8 +186,12 @@ subroutine test_make_directory_existing(error) ! Clean up: remove the empty directory call execute_command_line('rmdir ' // filename, exitstat=ios, cmdstat=iocmd, cmdmsg=msg) + if (allocated(error)) then + ! if previous error is allocated as well + call check(error, ios==0 .and. iocmd==0, error%message // ' and cannot cleanup make_directory test: '//trim(msg)) + return + end if call check(error, ios==0 .and. iocmd==0, 'Cannot cleanup make_directory test: '//trim(msg)) - if (allocated(error)) return end subroutine test_make_directory_existing subroutine test_remove_directory(error) @@ -209,8 +212,7 @@ subroutine test_remove_directory(error) if (allocated(error)) then ! Clean up: remove the empty directory call execute_command_line('rmdir ' // filename, exitstat=ios, cmdstat=iocmd, cmdmsg=msg) - call check(error, ios==0 .and. iocmd==0, 'Cannot cleanup make_directory test: '//trim(msg)) - if (allocated(error)) return + call check(error, ios==0 .and. iocmd==0, error%message // ' and cannot cleanup make_directory test: '//trim(msg)) end if end subroutine test_remove_directory From 7056a36759de5e67e6a8c9c62d93f81c47eec3e6 Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Sun, 6 Jul 2025 05:04:40 +0530 Subject: [PATCH 07/10] add subroutines and C wrappers --- src/stdlib_system.F90 | 82 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/stdlib_system.F90 b/src/stdlib_system.F90 index 2e0d3a1aa..9d7557bb9 100644 --- a/src/stdlib_system.F90 +++ b/src/stdlib_system.F90 @@ -130,6 +130,32 @@ module stdlib_system !! public :: remove_directory +!! version: experimental +!! +!! Gets the current working directory of the process +!! ([Specification](../page/specs/stdlib_system.html#get_cwd)) +!! +!! ### Summary +!! Gets the current working directory. +!! +!! ### Description +!! This subroutine gets the current working directory of the process calling this function. +!! +public :: get_cwd + +!! version: experimental +!! +!! Sets the current working directory of the process +!! ([Specification](../page/specs/stdlib_system.html#set_cwd)) +!! +!! ### Summary +!! Changes the current working directory to the one specified. +!! +!! ### Description +!! This subroutine sets the current working directory of the process calling this function to the one specified. +!! +public :: set_cwd + !! version: experimental !! !! Deletes a specified file from the filesystem. @@ -810,6 +836,62 @@ end function stdlib_remove_directory end select end subroutine remove_directory +subroutine get_cwd(cwd, err) + character(:), allocatable, intent(out) :: cwd + type(state_type), intent(out) :: err + type(state_type) :: err0 + + interface + type(c_ptr) function stdlib_get_cwd(len, stat) bind(C, name='stdlib_get_cwd') + import c_ptr, c_size_t + integer(c_size_t), intent(out) :: len + integer :: stat + end function stdlib_get_cwd + end interface + + type(c_ptr) :: c_str_ptr + integer(c_size_t) :: len, i + integer :: stat + character(kind=c_char), pointer :: c_str(:) + + c_str_ptr = stdlib_get_cwd(len, stat) + + if (stat /= 0) then + err0 = state_type(STDLIB_FS_ERROR, "code: ", to_string(stat)//",", c_get_strerror()) + call err0%handle(err) + end if + + call c_f_pointer(c_str_ptr, c_str, [len]) + + allocate(character(len=len) :: cwd) + + do concurrent (i=1:len) + cwd(i:i) = c_str(i) + end do +end subroutine get_cwd + +subroutine set_cwd(path, err) + character(len=*), intent(in) :: path + type(state_type), intent(out) :: err + type(state_type) :: err0 + + interface + integer function stdlib_set_cwd(path) bind(C, name='stdlib_set_cwd') + import c_char + character(kind=c_char), intent(in) :: path(*) + end function stdlib_set_cwd + end interface + + integer :: code + + code = stdlib_set_cwd(to_c_char(trim(path))) + + if (code /= 0) then + err0 = state_type(STDLIB_FS_ERROR, "code: ", to_string(code)//",", c_get_strerror()) + call err0%handle(err) + end if +end subroutine set_cwd + !> Returns the file path of the null device for the current operating system. !> !> Version: Helper function. From 988127f4015b866709707ca9bf9df68d4873080f Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Sun, 6 Jul 2025 05:04:57 +0530 Subject: [PATCH 08/10] add C functions --- src/stdlib_system.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/stdlib_system.c b/src/stdlib_system.c index 2d9368cc3..f3ca8da1d 100644 --- a/src/stdlib_system.c +++ b/src/stdlib_system.c @@ -1,4 +1,6 @@ +#include #include +#include #include #include #include @@ -44,3 +46,43 @@ int stdlib_remove_directory(const char* path){ return errno; } + +char* stdlib_get_cwd(size_t* len, int* stat){ + *stat = 0; +#ifdef _WIN32 + char* buffer; + buffer = _getcwd(NULL, 0); + + if (buffer == NULL) { + *stat = errno; + return NULL; + } + + *len = strlen(buffer) + return buffer; +#else + char buffer[PATH_MAX + 1]; + if (!getcwd(buffer, sizeof(buffer))) { + *stat = errno; + } + + *len = strlen(buffer); + + char* res = malloc(*len); + strncpy(res, buffer, *len); + + return res; +#endif /* ifdef _WIN32 */ +} + +int stdlib_set_cwd(char* path) { + int code; +#ifdef _WIN32 + code = _chdir(path); +#else + code = chdir(path); +#endif /* ifdef _WIN32 */ + + if (code == -1) return errno; + return 0; +} From d8fedab50f0c083faca7ecd60163752d5daf8acb Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Sun, 6 Jul 2025 05:05:21 +0530 Subject: [PATCH 09/10] add example --- example/system/CMakeLists.txt | 1 + example/system/example_cwd.f90 | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 example/system/example_cwd.f90 diff --git a/example/system/CMakeLists.txt b/example/system/CMakeLists.txt index 8189d525b..0784c9ad1 100644 --- a/example/system/CMakeLists.txt +++ b/example/system/CMakeLists.txt @@ -13,3 +13,4 @@ ADD_EXAMPLE(process_7) ADD_EXAMPLE(sleep) ADD_EXAMPLE(make_directory) ADD_EXAMPLE(remove_directory) +ADD_EXAMPLE(cwd) diff --git a/example/system/example_cwd.f90 b/example/system/example_cwd.f90 new file mode 100644 index 000000000..367a6f97e --- /dev/null +++ b/example/system/example_cwd.f90 @@ -0,0 +1,33 @@ +! Illustrate the usage of get_cwd, set_cwd +program example_cwd + use stdlib_system, only: get_cwd, set_cwd + use stdlib_error, only: state_type + implicit none + + character(len=:), allocatable :: path + type(state_type) :: err + + call get_cwd(path, err) + + if (err%error()) then + print *, "Error getting current working directory: "//err%print() + end if + + print *, "CWD: "//path + + call set_cwd("./src", err) + + if (err%error()) then + print *, "Error setting current working directory: "//err%print() + end if + + call get_cwd(path, err) + + if (err%error()) then + print *, "Error getting current working directory after using set_cwd: "//err%print() + return + end if + + print *, "CWD: "//path +end program example_cwd + From ae4dcc5d6b5e1c93536d517c8262c47b4c245339 Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Sun, 6 Jul 2025 05:05:33 +0530 Subject: [PATCH 10/10] add docs --- doc/specs/stdlib_system.md | 74 ++++++++++++++++++++++++++++++++++++++ src/stdlib_system.c | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/doc/specs/stdlib_system.md b/doc/specs/stdlib_system.md index bb5b1afa2..3806dfc91 100644 --- a/doc/specs/stdlib_system.md +++ b/doc/specs/stdlib_system.md @@ -532,6 +532,80 @@ The `err` is set accordingly. --- +## `get_cwd` - Gets the current working directory + +### Status + +Experimental + +### Description + +It gets the current working directory associated with the process calling this subroutine. +It is designed to work across multiple platforms. On Windows, paths with both forward `/` and backward `\` slashes are accepted. + +### Syntax + +`call [[stdlib_system(module):get_cwd(subroutine)]] (cwd, err)` + +### Class + +Subroutine + +### Arguments + +`cwd`: Shall be a character string containing the path of the current working directory (cwd). It is an `intent(out)` argument. + +`err`: Shall be of type `state_type`, for error handling. It is an `intent(out)` argument. + +### Return values + +The `err` is set accordingly. + +### Example + +```fortran +{!example/system/example_cwd.f90!} +``` + +--- + +## `set_cwd` - Sets the current working directory + +### Status + +Experimental + +### Description + +It sets the current working directory associated with the process calling this subroutine. +It is designed to work across multiple platforms. On Windows, paths with both forward `/` and backward `\` slashes are accepted. + +### Syntax + +`call [[stdlib_system(module):set_cwd(subroutine)]] (path, err)` + +### Class + +Subroutine + +### Arguments + +`path`: Shall be a character string containing the path of the directory. It is an `intent(in)` argument. + +`err`: Shall be of type `state_type`, for error handling. It is an `intent(out)` argument. + +### Return values + +The `err` is set accordingly. + +### Example + +```fortran +{!example/system/example_cwd.f90!} +``` + +--- + ## `null_device` - Return the null device file path ### Status diff --git a/src/stdlib_system.c b/src/stdlib_system.c index f3ca8da1d..280a3f880 100644 --- a/src/stdlib_system.c +++ b/src/stdlib_system.c @@ -58,7 +58,7 @@ char* stdlib_get_cwd(size_t* len, int* stat){ return NULL; } - *len = strlen(buffer) + *len = strlen(buffer); return buffer; #else char buffer[PATH_MAX + 1];