flibs/m_vfile - Manage exceptions
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 :
information, warning : just print a message and continue
error, fatal_error and failure : prints a message and stop the execution
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
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." )
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 ()
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
Generates a fatal error message and stops the execution.
Generates an error message and stops the execution.
Generates a warning message.
Generates an information message.
Generates a failure message and stops the execution
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.
Reset to 0 all the exceptions counters.
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
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.
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.
Returns the positive unit number onto which the messages are output, if enabled or a negative integer if the feature is disabled.
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.
Returns .true. if the current exception messages are written, either on standard output or into a log file.
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.
design a more powerful exception management system, which manages exceptions through the call stack.
Copyright © 2008 Michael Baudin michael.baudin@gmail.com
Copyright © 2008 Arjen Markus arjenmarkus@sourceforge.net