From c99a86f6457ffb87017968c5bbb3f8d0837212d4 Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Tue, 17 Jun 2025 23:16:50 +0530 Subject: [PATCH 1/4] added type and procedures --- src/stdlib_system.F90 | 75 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/stdlib_system.F90 b/src/stdlib_system.F90 index a9c3e4d55..d821fda4e 100644 --- a/src/stdlib_system.F90 +++ b/src/stdlib_system.F90 @@ -198,6 +198,32 @@ module stdlib_system end type process_type +! For Fileystem related error handling +type, public :: fs_error + ! the status code returned by C-functions or + ! global variables like `errno` etc whenever called + ! When no C interface is involved but there is an error it is set to -1 + integer :: code = 0 + + ! A user friendly message about the error + character(len=128) :: message = repeat(' ', 128) + +contains + ! resets the error state + procedure :: destroy => fs_error_destroy + + ! returns the formatted error message + procedure :: print => fs_error_message + + !> properties + procedure :: ok => fs_error_is_ok + procedure :: error => fs_error_is_error + + !> Handle optional error message + procedure :: handle => fs_error_handling + +end type fs_error + interface runasync !! version: experimental !! @@ -770,4 +796,53 @@ subroutine delete_file(path, err) end if end subroutine delete_file +elemental subroutine fs_error_destroy(this) + class(fs_error), intent(inout) :: this + + this%code = 0 + this%message = repeat(' ', len(this%message)) +end subroutine fs_error_destroy + +pure function fs_error_message(this) result(msg) + class(fs_error), intent(in) :: this + character(len=:), allocatable :: msg + character(len=7) :: tmp ! should be more than enough + + if (this%code == 0) then + msg = 'No Error!' + else + write(tmp, '(i0)') this%code + msg = 'Filesystem Error, code '//trim(tmp)//': '// trim(this%message) + end if +end function fs_error_message + +elemental function fs_error_is_ok(this) result(is_ok) + class(fs_error), intent(in) :: this + logical :: is_ok + is_ok = this%code == 0 +end function fs_error_is_ok + +elemental function fs_error_is_error(this) result(is_err) + class(fs_error), intent(in) :: this + logical :: is_err + is_err = this%code /= 0 +end function fs_error_is_error + +pure subroutine fs_error_handling(err,err_out) + class(fs_error), intent(in) :: err + class(fs_error), optional, intent(inout) :: err_out + + character(len=:),allocatable :: err_msg + + if (present(err_out)) then + ! copy err into err_out + err_out%code = err%code + err_out%message = err%message + else if (err%error()) then + ! stop the program + err_msg = err%print() + error stop err_msg + end if +end subroutine fs_error_handling + end module stdlib_system From 85b4ed80de99417f1694f9cb1ccfe16c9bbe426d Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Tue, 17 Jun 2025 23:17:04 +0530 Subject: [PATCH 2/4] added example --- example/system/CMakeLists.txt | 1 + example/system/example_fs_error.f90 | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 example/system/example_fs_error.f90 diff --git a/example/system/CMakeLists.txt b/example/system/CMakeLists.txt index a2a7525c9..9cdec1649 100644 --- a/example/system/CMakeLists.txt +++ b/example/system/CMakeLists.txt @@ -11,3 +11,4 @@ ADD_EXAMPLE(process_5) ADD_EXAMPLE(process_6) ADD_EXAMPLE(process_7) ADD_EXAMPLE(sleep) +ADD_EXAMPLE(fs_error) diff --git a/example/system/example_fs_error.f90 b/example/system/example_fs_error.f90 new file mode 100644 index 000000000..f3017c601 --- /dev/null +++ b/example/system/example_fs_error.f90 @@ -0,0 +1,27 @@ +program example_fs_error + use stdlib_system, only: fs_error + implicit none + + type(fs_error) :: err, err0 + + err = fs_error(1, 'Operation not permitted') ! EPERM + + ! Print message + print *, err%print() + + ! Check success + print *, 'Check error: ',err%error() + print *, 'Check flag : ',err%code /= 0 + + call err%handle(err0) + + ! Print flag + print *, err0%print() + + ! Check success + print *, 'Check error: ',err0%error() + print *, 'Check flag : ',err0%code /= 0 + + ! call err%handle() ! stops the program + +end program example_fs_error From 40132dd57047d0f5d097286c1c1ab9a902c5ff84 Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Tue, 17 Jun 2025 23:17:15 +0530 Subject: [PATCH 3/4] added docs --- doc/specs/stdlib_system.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/doc/specs/stdlib_system.md b/doc/specs/stdlib_system.md index 96eebb2e8..a8e32397d 100644 --- a/doc/specs/stdlib_system.md +++ b/doc/specs/stdlib_system.md @@ -9,6 +9,34 @@ and monitoring of system commands or applications directly from Fortran. [TOC] +## `fs_error` - A derived type for concise error handling + +### Status + +Experimental + +### Description + +The derived type contains a `code`, an integer and a fixed-length string containg a user friendly message. +The code is usually the one returned by C functions like `GetLastError` (Windows API) or global variables like `errno` (Unix platforms) +It is default initialized to `0` and it remains so if no errors occured. +In case the error is not because of any C functions, It is always set to `-1` (For distinguishability) + +### Type-bound Procedures + +The following convenience type-bound procedures are provided: +- `print()` returns a formatted allocatable character string containing the code and the message; +- `ok()` returns a `logical` flag that is `.true.` in case of no errors (`code == 0`); +- `error()` returns a `logical` flag that is `.true.` in case of an error (`code /= 0`). +- `handle([err])` assigns `err` to the calling variable or stops the program by calling `error stop` + +### Example + +``` +fortran +{!example/system/example_fs_error.f90!} +``` + ## `run` - Execute an external process synchronously ### Status From bd38b94f9232d765c068f1c794acd4d09155f661 Mon Sep 17 00:00:00 2001 From: "supritsj@Arch" Date: Tue, 17 Jun 2025 23:39:27 +0530 Subject: [PATCH 4/4] added operators ==, /= --- doc/specs/stdlib_system.md | 4 ++++ example/system/example_fs_error.f90 | 8 +++---- src/stdlib_system.F90 | 37 +++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/doc/specs/stdlib_system.md b/doc/specs/stdlib_system.md index a8e32397d..949b97506 100644 --- a/doc/specs/stdlib_system.md +++ b/doc/specs/stdlib_system.md @@ -30,6 +30,10 @@ The following convenience type-bound procedures are provided: - `error()` returns a `logical` flag that is `.true.` in case of an error (`code /= 0`). - `handle([err])` assigns `err` to the calling variable or stops the program by calling `error stop` +### Overloaded Operators + +operators `==`, `/=` are provided for comparing `type(fs_error)` variables and `integer` codes. + ### Example ``` diff --git a/example/system/example_fs_error.f90 b/example/system/example_fs_error.f90 index f3017c601..c61431890 100644 --- a/example/system/example_fs_error.f90 +++ b/example/system/example_fs_error.f90 @@ -1,5 +1,5 @@ program example_fs_error - use stdlib_system, only: fs_error + use stdlib_system, only: fs_error, operator(/=) implicit none type(fs_error) :: err, err0 @@ -11,16 +11,16 @@ program example_fs_error ! Check success print *, 'Check error: ',err%error() - print *, 'Check flag : ',err%code /= 0 + print *, 'Check flag : ',err /= 0 call err%handle(err0) - ! Print flag + ! Print message print *, err0%print() ! Check success print *, 'Check error: ',err0%error() - print *, 'Check flag : ',err0%code /= 0 + print *, 'Check flag : ',err0 /= 0 ! call err%handle() ! stops the program diff --git a/src/stdlib_system.F90 b/src/stdlib_system.F90 index d821fda4e..a09d0ece3 100644 --- a/src/stdlib_system.F90 +++ b/src/stdlib_system.F90 @@ -224,6 +224,19 @@ module stdlib_system end type fs_error +interface operator(==) + module procedure code_eq_err + module procedure err_eq_code +end interface operator(==) + +interface operator(/=) + module procedure code_neq_err + module procedure err_neq_code +end interface operator(/=) + +public :: operator(==) +public :: operator(/=) + interface runasync !! version: experimental !! @@ -845,4 +858,28 @@ pure subroutine fs_error_handling(err,err_out) end if end subroutine fs_error_handling +pure logical function code_eq_err(code, err) + integer, intent(in) :: code + type(fs_error), intent(in) :: err + code_eq_err = code == err%code +end function code_eq_err + +pure logical function err_eq_code(err, code) + integer, intent(in):: code + type(fs_error), intent(in) :: err + err_eq_code = code == err%code +end function err_eq_code + +pure logical function code_neq_err(code, err) + integer, intent(in) :: code + type(fs_error), intent(in) :: err + code_neq_err = code /= err%code +end function code_neq_err + +pure logical function err_neq_code(err, code) + integer, intent(in) :: code + type(fs_error), intent(in) :: err + err_neq_code = code /= err%code +end function err_neq_code + end module stdlib_system