Skip to content

helper functions for Fileysystem error handling #1015

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions doc/specs/stdlib_system.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,83 @@ Returns one of the `integer` `OS_*` parameters representing the OS type, from th

---

## `fs_error` - Helper function for error handling

### Status

Experimental

### Description

A helper function for returning the `type(state_type)` with the flag `STDLIB_FS_ERROR` set.

### Syntax

`err = fs_error([a1,a2,a3,a4...... a20])`

### Class
Pure Function

### Arguments

`a1,a2,a3.....a20`(optional) : They are of type `class(*), dimension(..), optional, intent(in)`.
An arbitrary list of `integer`, `real`, `complex`, or `character` variables. Numeric variables may be provided as either scalars or rank-1 (array) inputs.

### Behavior

Formats all the arguments into a nice error message, utilizing the constructor of [[stdlib_system(module):state_type(type)]]

### Return values

`type(state_type)`

### Example

```fortran
{!example/system/example_fs_error.f90!}
```

---

## `fs_error_code` - Helper function for error handling (with error code)

### Status

Experimental

### Description

A helper function for returning the `type(state_type)` with the flag `STDLIB_FS_ERROR` set.
It also formats and prefixes the `code` passed to it as the first argument.

### Syntax

`err = fs_error(code [, a1,a2,a3,a4...... a19])`

### Class
Pure Function

### Arguments

`a1,a2,a3.....a19`: They are of type `class(*), dimension(..), optional, intent(in)`.
An arbitrary list of `integer`, `real`, `complex`, or `character` variables. Numeric variables may be provided as either scalars or rank-1 (array) inputs.

### Behavior

Formats all the arguments into a nice error message, utilizing the constructor of [[stdlib_system(module):state_type(type)]]

### Return values

`type(state_type)`

### Example

```fortran
{!example/system/example_fs_error.f90!}
```

---

## `is_directory` - Test if a path is a directory

### Status
Expand Down
1 change: 1 addition & 0 deletions example/system/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ ADD_EXAMPLE(process_5)
ADD_EXAMPLE(process_6)
ADD_EXAMPLE(process_7)
ADD_EXAMPLE(sleep)
ADD_EXAMPLE(fs_error)
23 changes: 23 additions & 0 deletions example/system/example_fs_error.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
! Demonstrate usage of `fs_error`, `fs_error_code`
program example_fs_error
use stdlib_system, only: fs_error, fs_error_code
use stdlib_error, only: state_type, STDLIB_FS_ERROR
implicit none

type(state_type) :: err0, err1

err0 = fs_error("Could not create directory", "`temp.dir`", "- Already exists")

if (err0%state == STDLIB_FS_ERROR) then
! Error encountered: Filesystem Error: Could not create directory `temp.dir` - Already exists
print *, err0%print()
end if

err1 = fs_error_code(1, "Could not create directory", "`temp.dir`", "- Already exists")

if (err1%state == STDLIB_FS_ERROR) then
! Error encountered: Filesystem Error: code - 1, Could not create directory `temp.dir` - Already exists
print *, err1%print()
end if

end program example_fs_error
47 changes: 46 additions & 1 deletion src/stdlib_system.F90
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -133,6 +133,21 @@ module stdlib_system
!! On Windows, this is `NUL`. On UNIX-like systems, this is `/dev/null`.
!!
public :: null_device

!! version: experimental
!!
!! A helper function for returning the `type(state_type)` with the flag `STDLIB_FS_ERROR` set.
!! ([Specification](../page/specs/stdlib_system.html#fs_error))
!!
public :: fs_error

!! version: experimental
!!
!! A helper function for returning the `type(state_type)` with the flag `STDLIB_FS_ERROR` set.
!! It also formats and prefixes the `code` passed to it as the first argument
!! ([Specification](../page/specs/stdlib_system.html#fs_error_code))
!!
public :: fs_error_code

! CPU clock ticks storage
integer, parameter, private :: TICKS = int64
Expand Down Expand Up @@ -770,4 +785,34 @@ subroutine delete_file(path, err)
end if
end subroutine delete_file

pure function fs_error_code(code,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10, &
a11,a12,a13,a14,a15,a16,a17,a18, a19) result(state)

type(state_type) :: state
!> Platform specific error code
integer, intent(in) :: code
!> Optional rank-agnostic arguments
class(*), intent(in), optional, dimension(..) :: a1,a2,a3,a4,a5,a6,a7,a8,a9,a10, &
a11,a12,a13,a14,a15,a16,a17,a18, a19

character(32) :: code_msg

write(code_msg, "('code - ', i0, ',')") code

state = state_type(STDLIB_FS_ERROR, code_msg,a1,a2,a3,a4,a5,a6,a7,a8, &
a9,a10,a11,a12,a13,a14,a15,a16,a17,a18, a19)
end function fs_error_code

pure function fs_error(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11, &
a12,a13,a14,a15,a16,a17,a18,a19,a20) result(state)

type(state_type) :: state
!> Optional rank-agnostic arguments
class(*), intent(in), optional, dimension(..) :: a1,a2,a3,a4,a5,a6,a7,a8,a9,a10, &
a11,a12,a13,a14,a15,a16,a17,a18,a19,a20

state = state_type(STDLIB_FS_ERROR, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12, &
a13,a14,a15,a16,a17,a18,a19,a20)
end function fs_error

end module stdlib_system
25 changes: 23 additions & 2 deletions test/system/test_filesystem.f90
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
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_error, only: state_type
use stdlib_system, only: is_directory, delete_file, fs_error, fs_error_code
use stdlib_error, only: state_type, STDLIB_FS_ERROR

implicit none

Expand All @@ -13,6 +13,7 @@ subroutine collect_suite(testsuite)
type(unittest_type), allocatable, intent(out) :: testsuite(:)

testsuite = [ &
new_unittest("fs_error", test_FS_ERROR), &
new_unittest("fs_is_directory_dir", test_is_directory_dir), &
new_unittest("fs_is_directory_file", test_is_directory_file), &
new_unittest("fs_delete_non_existent", test_delete_file_non_existent), &
Expand All @@ -21,6 +22,26 @@ subroutine collect_suite(testsuite)
]
end subroutine collect_suite

subroutine test_fs_error(error)
type(error_type), allocatable, intent(out) :: error
type(state_type) :: s1, s2
character(:), allocatable :: msg

msg = "code - 10, Cannot create File temp.txt - File already exists"
s1 = fs_error_code(10, "Cannot create File temp.txt -", "File already exists")

call check(error, s1%state == STDLIB_FS_ERROR .and. s1%message == msg, &
"fs_error_code: Could not construct the state with code correctly")
if (allocated(error)) return

msg = "Cannot create File temp.txt - File already exists"
s2 = fs_error("Cannot create File temp.txt -", "File already exists")

call check(error, s2%state == STDLIB_FS_ERROR .and. s2%message == msg, &
"fs_error: Could not construct state without code correctly")
if (allocated(error)) return
end subroutine test_fs_error

! Test `is_directory` for a directory
subroutine test_is_directory_dir(error)
type(error_type), allocatable, intent(out) :: error
Expand Down
Loading