flibs/m_vfile(n) 1.0 "flibs"

Name

flibs/m_vfile - Manage exceptions

Table Of Contents

Synopsis

Description

Provides services to generate different levels of exceptions and display the message of the exception. Five levels of exceptions can be generated, from the lowest to the highest level :

OVERVIEW

Simple use-case

Suppose that one would like to compute the square root of one real value. The "compute_sqrt" function takes one positive real argument, and if the argument is negative, one cannot compute the square root so that one would generate an error. In the following example, extracted from the unit tests included in the project, one uses the static method "exception_raiseError" to display a user-friendly message and stop the execution of the program

    function compute_sqrt ( value ) result ( root )
      use m_exception
      implicit none
      real, intent(in) :: value
      real :: root
      if ( value < 0. ) then
        call exception_raiseError ( "Value is negative in compute_sqrt" )
      else 
        root = sqrt ( value )
      endif
   end function compute_sqrt
   real :: root
   root = compute_sqrt ( -1. )

In the previous example, the standard output is written so that the following message appears on screen.

   Error.
   Message: Value is negative in compute_sqrt

Controlling the execution

The client code can control the behaviour of the component each time an exception is raised. The default behaviour is to stop the execution. This can be modified by calling "exception_setstoponerror" in order to continue the execution, even if error, fatal error or failure exceptions are raised.

In the following example, the static method "exception_setstoponerror" is called so that an error does not interrupt the execution.

   call exception_setstoponerror ( .false. )
   call exception_raiseError ( "There is an error, but the execution will continue." )

Controlling output

The default behaviour is to write messages onto the standard output each time an exception is raised. This can be modified in two ways.

  • the first possibility is to disable the writing of the messages with "exception_logactive". This feature might be useful in the case where a component has known bugs but generates lots of unwanted exceptions messages.

  • the second possibility is to connect the component to an existing unit with "exception_setlogunit", so that the messages are written on the given logical unit number. This allows for example to write on an existing log file, may be the log file manage by the m_logger component included in the project.

In the following example, the client code first disables all output, set "stoponerror" to false and generates an error which is not displayed and does not interrupt the execution.

   call exception_setstoponerror ( .false. )
   call exception_logactive ( .false. )
   call exception_raiseError ( "This message will not be displayed and the execution will continue." )
   call exception_logactive ( .true. )
   call exception_raiseError ( "This message WILL be displayed and the execution will continue." )

In the following example, the client code connect the m_exception component to an existing unit so that the exception messages are written onto a client log file.

     log_fileunit = 12
     call exception_setstoponerror ( .false. )
     open ( log_fileunit , FILE= "log_file.log" )
     call exception_setlogunit ( log_fileunit )
     call exception_raiseError ( "This message will be written in log_file.log and the execution will continue." )
     call exception_setlogunit ( 0 )
     call exception_raiseError ( "This message will be written on standard output and the execution will continue." )
     close ( log_fileunit )

In the following example, the client code connects the m_exception component to the logfile manage by m_logger. This way, the exception messages are collected in the unique log file of the client code.

     call log_startup ( "log_file.log" , append=.true. )
     call log_cget ( "logfileunit" , log_fileunit )
     call exception_setstoponerror ( .false. )
     call exception_setlogunit ( log_fileunit )
     call exception_raiseError ( "This message will be written in log_file.log and the execution will continue." )
     call log_shutdown ()

Pseudo-catch

The client code can use a pseudo-catch system which provides a simple way to manage exceptions which are raised at a lower level in the call stack. This allows to provide special treatments when exceptions are generated, without modifiying all lower level subroutines/function, but just by inserting exception management when needed. Suppose that you have a subroutine which source code is the following.

     subroutine yoursubroutine ()
       use m_exception, only : exception_raiseFatalError
       implicit none
       [...]
       call exception_raiseFatalError ( "Wrong blabla in yoursubroutine" )
       [...]
     end subroutine yoursubroutine

When calling the subroutine "yoursubroutine", one may wonder if exceptions have been generated so that these errors may be processed, or not. One can use the "exception_catch" service to compute the status of one subroutine and manage that status.

     use m_exception, only : exception_catch, &
         EXCEPTION_INFORMATION, &
         EXCEPTION_WARNING &
         EXCEPTION_ERROR &
         EXCEPTION_FATAL_ERROR &
         EXCEPTION_FAILURE
     integer :: status
     call exception_catch ( yoursubroutine , status )
     select case ( status )
     case ( EXCEPTION_INFORMATION )
        write(6,*) "Information"
     case ( EXCEPTION_WARNING )
        write(6,*) "Warning"
     case ( EXCEPTION_ERROR , EXCEPTION_FATAL_ERROR , EXCEPTION_FAILURE )
        write(6,*) "Fatal error"
     case default
        write(6,*) "No problem, continue."
     end select

ROUTINES

exception_raiseFatalError ( message )
character(len=*), intent(in) :: message

Generates a fatal error message and stops the execution.

exception_raiseError ( message )
character(len=*), intent(in) :: message

Generates an error message and stops the execution.

exception_raiseWarning ( message )
character(len=*), intent(in) :: message

Generates a warning message.

exception_raiseInformation ( message )
character(len=*), intent(in) :: message

Generates an information message.

exception_raiseFailure ( message )
character(len=*), intent(in) :: message

Generates a failure message and stops the execution

exception_setstoponerror ( stoponerror )
logical, intent(in) :: message

If stoponerror is true, then when an error, a fatal_error or a failure is generated, then stop the execution. If stoponerror is false, then the same exceptions do not stop the execution.

exception_initcounter ( )
logical, intent(in) :: message

Reset to 0 all the exceptions counters.

exception_getcounter ( )
integer, dimension(1:EXCEPTION_SIZE), intent(out) :: counter

Returns an array of size EXCEPTION_SIZE indicating the number of exceptions of each type. The value of excepcounters ( iexcept ) is the total number of exceptions of type #iexcept generated since the begining of the execution. The possible values for iexcept are the following.

  • counter ( EXCEPTION_INFORMATION ) : total number of information exceptions raised

  • counter ( EXCEPTION_WARNING ) : total number of warning exceptions raised

  • counter ( EXCEPTION_ERROR ) : total number of error exceptions raised

  • counter ( EXCEPTION_FATAL_ERROR ) : total number of fatal error exceptions raised

  • counter ( EXCEPTION_FAILURE ) : total number of failure exceptions raised

exception_report ( )

Writes on the current exception unit number a report which details the number of exceptions of all types since the begining of the execution or the last reset of all counters.

exception_setlogunit ( unitnumber )
integer, intent(in) :: unitnumber

Set the unit number onto which the messages are output. If the unitnumber is negative or 0, the messages are written to the standard output (unit *). Note : a unitnumber equals to 6 is generally the standard output, but this may depend on the fortran compiler.

exception_getlogunit ( ) result ( logunit )
integer :: logunit

Returns the positive unit number onto which the messages are output, if enabled or a negative integer if the feature is disabled.

exception_logactive ( bool )
logical, intent(in) :: bool

If the boolean argument bool is true, enable the logging of the exceptions messages. If the boolean argument bool is false, disable the logging of the exceptions messages.

exception_islogactive ( ) result ( islogactive )
logical :: islogactive

Returns .true. if the current exception messages are written, either on standard output or into a log file.

exception_catch ( callback , status ) result ( islogactive )
integer, intent(out) :: status
    interface interfacecallback
       subroutine callback ()
       end subroutine callback
    end interface interfacecallback

Calls the given subroutine callback and set status as an the integer associated with last exception, higher level, code or 0 if no exception was raised. Caution : the internal algorithm is based on the exception counters, which implies that any call to exception_initcounter in the client code can result in a wrong status.

TODO