OODuck
0.5
C Oriented Object framework with duck-typing support
|
Exceptions4C library. More...
Files | |
file | e4c.h |
Classes | |
struct | e4c_exception_type |
struct | e4c_exception |
struct | e4c_signal_mapping |
Typedefs | |
typedef void(* | e4c_uncaught_handler) (const e4c_exception *exception) |
typedef void *(* | e4c_initialize_handler) (const e4c_exception *exception) |
typedef void(* | e4c_finalize_handler) (void *custom_data) |
Enumerations | |
enum | e4c_status_ { e4c_succeeded, e4c_recovered, e4c_failed } |
Exception handling keywords | |
This set of keywords express the semantics of exception handling. | |
#define | try E4C_TRY |
#define | catch(exception_type) E4C_CATCH(exception_type) |
#define | finally E4C_FINALLY |
#define | retry(max_retry_attempts) E4C_RETRY(max_retry_attempts) |
#define | throw(exception_type, message) E4C_THROW(exception_type, message) |
#define | rethrow(message) E4C_RETHROW(message) |
Dispose pattern keywords | |
This set of keywords express the semantics of automatic resource acquisition and disposal. | |
#define | with(resource, dispose) E4C_WITH(resource, dispose) |
#define | use E4C_USE |
#define | using(type, resource, args) E4C_USING(type, resource, args) |
#define | reacquire(max_reacquire_attempts) E4C_REACQUIRE(max_reacquire_attempts) |
Integration macros | |
These macros are designed to ease the integration of external libraries which make use of the exception handling system. | |
#define | E4C_VERSION_NUMBER |
#define | E4C_VERSION_THREADSAFE |
#define | E4C_VERSION_MAJOR |
#define | E4C_VERSION_MINOR |
#define | E4C_VERSION_REVISION |
#define | E4C_VERSION_STRING |
#define | E4C_EXCEPTION_MESSAGE_SIZE 128 |
#define | e4c_reusing_context(status, on_failure) E4C_REUSING_CONTEXT(status, on_failure) |
#define | E4C_ON_FAILURE(handler) handler( e4c_get_exception() ) |
#define | E4C_NO_RETURN |
#define | E4C_UNREACHABLE_RETURN(value) |
#define | E4C_UNREACHABLE_VOID_RETURN |
Other convenience macros | |
These macros provide a handy way to: begin (and end) implicitly a new exception context, express assertions, define and declare exceptions, and define arrays of signal mappings. | |
#define | e4c_using_context(handle_signals) E4C_USING_CONTEXT(handle_signals) |
#define | assert(condition) E4C_ASSERT(condition) |
#define | E4C_DECLARE_EXCEPTION(name) |
#define | E4C_DEFINE_EXCEPTION(name, default_message, supertype) |
#define | E4C_SIGNAL_MAPPING(signal_number, exception_type) |
#define | E4C_IGNORE_SIGNAL(signal_number) |
#define | E4C_NULL_SIGNAL_MAPPING |
Predefined signal mappings | |
There is a predefined set of signal mappings. Signal mappings are used to convert signals into exceptions. Common signals are mapped to its corresponding exception, for example:
| |
const e4c_signal_mapping *const | e4c_default_signal_mappings |
Predefined exceptions | |
Built-in exceptions represent usual error conditions that might occur during the course of any program. They are organized into a pseudo-hierarchy; | |
E4C_DECLARE_EXCEPTION (RuntimeException) | |
E4C_DECLARE_EXCEPTION (NotEnoughMemoryException) | |
E4C_DECLARE_EXCEPTION (IllegalArgumentException) | |
E4C_DECLARE_EXCEPTION (AssertionException) | |
E4C_DECLARE_EXCEPTION (InputOutputException) | |
E4C_DECLARE_EXCEPTION (SignalException) | |
E4C_DECLARE_EXCEPTION (SignalAlarmException) | |
E4C_DECLARE_EXCEPTION (SignalChildException) | |
E4C_DECLARE_EXCEPTION (SignalTrapException) | |
E4C_DECLARE_EXCEPTION (ErrorSignalException) | |
E4C_DECLARE_EXCEPTION (IllegalInstructionException) | |
E4C_DECLARE_EXCEPTION (ArithmeticException) | |
E4C_DECLARE_EXCEPTION (BrokenPipeException) | |
E4C_DECLARE_EXCEPTION (BadPointerException) | |
E4C_DECLARE_EXCEPTION (NullPointerException) | |
E4C_DECLARE_EXCEPTION (ControlSignalException) | |
E4C_DECLARE_EXCEPTION (StopException) | |
E4C_DECLARE_EXCEPTION (KillException) | |
E4C_DECLARE_EXCEPTION (HangUpException) | |
E4C_DECLARE_EXCEPTION (TerminationException) | |
E4C_DECLARE_EXCEPTION (AbortException) | |
E4C_DECLARE_EXCEPTION (CPUTimeException) | |
E4C_DECLARE_EXCEPTION (UserControlSignalException) | |
E4C_DECLARE_EXCEPTION (UserQuitException) | |
E4C_DECLARE_EXCEPTION (UserInterruptionException) | |
E4C_DECLARE_EXCEPTION (UserBreakException) | |
E4C_DECLARE_EXCEPTION (ProgramSignalException) | |
E4C_DECLARE_EXCEPTION (ProgramSignal1Exception) | |
E4C_DECLARE_EXCEPTION (ProgramSignal2Exception) | |
Exception context handling functions | |
These functions enclose the scope of the exception handling system and retrieve the current exception context. | |
E4C_BOOL | e4c_context_is_ready (void) |
void | e4c_context_begin (E4C_BOOL handle_signals) |
void | e4c_context_end (void) |
void | e4c_context_set_handlers (e4c_uncaught_handler uncaught_handler, void *custom_data, e4c_initialize_handler initialize_handler, e4c_finalize_handler finalize_handler) |
void | e4c_context_set_signal_mappings (const e4c_signal_mapping *mappings) |
const e4c_signal_mapping * | e4c_context_get_signal_mappings (void) |
e4c_status | e4c_get_status (void) |
const e4c_exception * | e4c_get_exception (void) |
Other integration and convenience functions | |
long | e4c_library_version (void) |
E4C_BOOL | e4c_is_instance_of (const e4c_exception *instance, const e4c_exception_type *exception_type) |
void | e4c_print_exception (const e4c_exception *exception) |
void | e4c_print_exception_type (const e4c_exception_type *exception_type) |
Exceptions4C library.
#define assert | ( | condition | ) | E4C_ASSERT(condition) |
Expresses a program assertion
condition | A predicate that must evaluate to true |
An assertion is a mechanism to express that the developer thinks that a specific condition is always met at some point of the program.
assert
is a convenient way to insert debugging assertions into a program. The NDEBUG
compile-time parameter determines whether the assumptions will be actually verified by the program at run-time.
In presence of NDEBUG
, the assertion statements will be ignored and therefore will have no effects on the program, not even evaluating the condition. Therefore expressions passed to assert
must not contain side-effects, since they will not take place when debugging is disabled.
In absence of NDEBUG
, the assertion statements will verify that the condition is met every time the program reaches that point of the program.
If the assertion does not hold at any time, then an #AssertionException
will be thrown to indicate the programming error. This exception cannot be caught whatsoever. The program (or current thread) will be terminated.
The main advantage of using this assertion mechanism (as opposed to the macros provided by the standard header file assert.h
) is that all of the pending finally
blocks will be executed, before actually exiting the program or thread.
assert
. Such programming error will lead to an abrupt exit of the program (or thread).#define catch | ( | exception_type | ) | E4C_CATCH(exception_type) |
Introduces a block of code capable of handling a specific type of exceptions
exception_type | The type of exceptions to be handled |
catch
blocks are optional code blocks that must be preceded by try
, with
... use
or using
blocks. Several catch
blocks can be placed next to one another.
When an exception is thrown, the system looks for a catch
block to handle it. The first capable block (in order of appearance) will be executed. The exception is said to be caught and the try
block is in recovered (status)[@ ref e4c_status].
The caught exception can be accessed through the function e4c_get_exception.
The actual type of the exception can be checked against other exception types through the function e4c_is_instance_of.
The type might also be compared directly against another specific exception type.
After the catch
block completes, the finally
block (if any) is executed. Then the program continues by the next line following the set of try
... catch
... finally
blocks.
However, if an exception is thrown in a catch
block, then the finally
block will be executed right away and the system will look for an outter catch
block to handle it.
Only one of all the catch
blocks will be executed for each try
block, even though the executed catch
block throws another exception. The only possible way to execute more than one catch
block would be by retry
ing the entire try
block.
#define E4C_DECLARE_EXCEPTION | ( | name | ) |
Throws an exception with a formatted message
exception_type | The type of exception to be thrown |
format | The string containing the specifications that determine the output format for the variadic arguments |
... | The variadic arguments that will be formatted according to the format control |
This is a handy way to compose a formatted message and throw
an exception on the fly:
This macro relies on two features that were introduced in the ISO/IEC 9899:1999 (also known as C99) revision of the C programming language standard in 1999:
vsnprintf
In order not to create compatibility issues, this macro will only be defined when the __STDC_VERSION__
compile-time parameter is defined as a long
value greater than or equal to 199901L
, or when HAVE_C99_VARIADIC_MACROS
is defined.
The semantics of this keyword are the same as for throw
.
throwf
. Such programming error will lead to an abrupt exit of the program (or thread).vsnprintf
with the specified format and variadic arguments. For further information on formatting rules, you may look up the specifications for the function vsnprintf
. throwf
point.format | The string containing the specifications that determine the output format for the variadic arguments. |
... | The variadic arguments that will be formatted according to the format control. |
This is a handy way to create (and then throw
) a new instance of the currently thrown exception, with a more specific, formatted message.
This macro relies on two features that were introduced in the ISO/IEC 9899:1999 (also known as C99) revision of the C programming language standard in 1999:
vsnprintf
In order not to create compatibility issues, this macro will only be defined when the __STDC_VERSION__
compile-time parameter is defined as a long
value greater than or equal to 199901L
, or when HAVE_C99_VARIADIC_MACROS
is defined.
The semantics of this keyword are the same as for throw
.
rethrowf
. Such programming error will lead to an abrupt exit of the program (or thread).vsnprintf
with the specified format and variadic arguments. For further information on formatting rules, you may look up the specifications for the function vsnprintf
. rethrowf
point.name | Name of the exception type |
This macro introduces the name of an extern
, const
exception type which will be available to be thrown or caught:
This macro is intended to be used inside header files.
E4C_DEFINE_EXCEPTION
.#define E4C_DEFINE_EXCEPTION | ( | name, | |
default_message, | |||
supertype | |||
) |
Defines an exception type
name | Name of the new exception type |
default_message | Default message of the new exception type |
supertype | Supertype of the new exception type |
This macro allocates a new, const
exception type.
This macro is intended to be used inside sorce code files. The defined exception types can be declared in a header file through the macro E4C_DECLARE_EXCEPTION
.
#define E4C_EXCEPTION_MESSAGE_SIZE 128 |
Provides the maximum length (in bytes) of an exception message
#define E4C_IGNORE_SIGNAL | ( | signal_number | ) |
Ignores a specific signal number
signal_number | Numeric value of the signal to be ignored |
This macro represents a signal mapping literal. It comes in handy for initializing arrays of signal mappings.
#define E4C_NO_RETURN |
Marks a function which never returns
This macro helps both developer and compiler to assume that the marked function will not return the control to its caller (unless by throwing an exception).
void
.For example, a function f1
that always throws an exception, could be marked with this macro:
Then, if another function tested a condition and then called f1
, it wouldn't need to return anything witnin the if
branch, nor consider the else
branch of the test:
If the compiler supports this macro, it could optimize the program and avoid spurious warnings of uninitialized variables.
#define E4C_NULL_SIGNAL_MAPPING |
Represents a null signal mapping literal
This macro represents a null signal mapping literal. It comes in handy for terminating arrays of #e4c_signal_mapping
.
#define E4C_ON_FAILURE | ( | handler | ) | handler( e4c_get_exception() ) |
Provides a means of parsing an exception to obtain a status value
handler | The name of the parser function to be called |
This is a handy way to call a function when a e4c_reusing_context block fails. This function will be passed the current thrown exception; it is expected to parse it and return a proper status
value.
#define e4c_reusing_context | ( | status, | |
on_failure | |||
) | E4C_REUSING_CONTEXT(status, on_failure) |
Reuses an existing exception context, otherwise, begins a new one and then ends it.
status | The name of a previously defined variable, or lvalue, which will be assigned the specified failure value |
on_failure | A constant value or expression that will be assigned to the specified lvalue in case of failure |
This macro lets library developers use the exception framework, regardless of whether the library clients are unaware of the exception handling system. In a nutshell, function libraries can use try
, catch
, throw
, etc. whether the client previously began an exception context or not.
You must not use this macro unless you are implementing some functionality which is to be called from another program, potentially unaware of exceptions.
When the block completes, the system returns to its previous status (if it was required to open a new exception context, then it will be automatically closed).
This way, when an external function encounters an error, it may either throw an exception (when the caller is aware of the exception system), or otherwise return an error code (when the caller did not open an exception context).
e4c_reusing_context
takes two parameters:
status
(lvalue)on_failure
(rvalue)status
must will be assigned on_failure
if, and only if, an exception is thrown inside the block. Needless to say, on_failure
may be an expression assignable to status
.
status
will be left unmodified if the client (i.e. the function caller) is exception-aware, or the block completes without an error (i.e. no exception is thrown), so it must be properly initialized before returning it.
Please note that status
doesn't have to be just a dichotomy (success or failure). It can be a fine-grained value describing what exactly went wrong. You can pass any expression to e4c_reusing_context
as on_failure
; it will be evaluated when an exception is thrown:
However, Most of the times you probably want to yield a different status value depending on the specific exception being thrown. This can be easily accomplished by making use of the macro E4C_ON_FAILURE
.
Next, the semantics of e4c_reusing_context
are explained, step by step:
status
will be asigned the value of the expression on_failure
.If you need to perform any cleanup, you should place it inside a finally
block.
If you need to rely on the signal handling system, you may call e4c_context_set_signal_mappings
explicitly. You should take into account that you could be hijacking your client's original signal mappings, so you should also call e4c_context_get_signal_mappings
in order to restore the previous signal mappings when you are done.
This macro only begins a new exception context if there is no one, already begun, to be used whereas e4c_using_context
always attempts to begin a new one.
e4c_reusing_context
must not be exited through any of: goto
, break
, continue
or return
(but it is legal to throw
an exception). e4c_reusing_context
is guaranteed to take place inside an exception context.#define E4C_SIGNAL_MAPPING | ( | signal_number, | |
exception_type | |||
) |
Maps a specific signal number to a given exception type
signal_number | Numeric value of the signal to be converted |
exception_type | Exception type representing the signal |
This macro represents a signal mapping literal. It comes in handy for initializing arrays of signal mappings.
#define E4C_UNREACHABLE_RETURN | ( | value | ) |
Simulates a function return
value | The value that would be returned if the statement took place. |
This macro ensures portability on compilers which don't support functions that never return.
It may be used after calling a function marked as E4C_NO_RETURN
, so that the compiler will not complain about control reaching end of non-void function. For example:
This macro will become an actual return
statement if the compiler does not support E4C_NO_RETURN
, even though it will never be reached (because the called function won't actually return control).
#define E4C_UNREACHABLE_VOID_RETURN |
Simulates a function void return
This macro ensures portability on static source code analyzers which don't support functions that never return.
It may be used after calling a function marked as E4C_NO_RETURN
, so that the analyzer will not complain about spurious errors. For example, if we didn't use E4C_UNREACHABLE_VOID_RETURN
here, some analyzers might complain about possible null pointer dereference at line foo = *bar
, because they are not aware that function call f1(321);
will never return control:
This macro will become an actual return
statement if the compiler does not support E4C_NO_RETURN
, even though it will never be reached (because the called function won't actually return control).
#define e4c_using_context | ( | handle_signals | ) | E4C_USING_CONTEXT(handle_signals) |
Introduces a block of code which will use a new exception context.
handle_signals | If true , the signal handling system will be set up with the default mapping. |
This macro begins a new exception context to be used by the code block right next to it. When the code completes, e4c_context_end
will be called implicitly.
This macro is very convenient when the beginning and the ending of the current exception context are next to each other. For example, there is no semantic difference between this two blocks of code:
This macro always attempts to begin a new exception context, whereas e4c_reusing_context
only does if there is no exception context, already begun, to be used.
This macro should be used whenever possible, rather than doing the explicit, manual calls to e4c_context_begin
and e4c_context_end
, because it is less prone to errors.
e4c_using_context
must not be exited through any of: goto
, break
, continue
or return
(but it is legal to throw
an exception). e4c_using_context
is guaranteed to take place inside an exception context.#define E4C_VERSION_MAJOR |
Provides the library major version number
The library major version number is an int
value which is incremented from one release to another when there are significant changes in functionality.
#define E4C_VERSION_MINOR |
Provides the library minor version number
The library minor version number is an int
value which is incremented from one release to another when only minor features or significant fixes have been added.
#define E4C_VERSION_NUMBER |
Provides the library version number
The library version number is a long
value which expresses:
The multi-thread (or thread-safe) mode can be enabled by compiling the library with the E4C_THREADSAFE
compile-time parameter.
The formula to encode these version numbers into a single long
value is:
These numbers can be obtained separately through the next macros:
The library version number can be also obtained as a string literal in the format "MAJOR.MINOR.REVISION (THREADSAFE)" through the macro E4C_VERSION_STRING
.
e4c_library_version
.#define E4C_VERSION_REVISION |
Provides the library revision number
The library revision number is an int
value which is incremented from one release to another when minor bugs are fixed.
#define E4C_VERSION_STRING |
Provides the library version number as a string literal
The format of the string literal is: "MAJOR.MINOR.REVISION (THREADSAFE)".
#define E4C_VERSION_THREADSAFE |
Provides the library thread mode (either single-thread or multi-thread)
When the library is compiled with the E4C_THREADSAFE
compile-time parameter, E4C_VERSION_THREADSAFE
will yield the int
value 1
(meaning multi-thread mode), otherwise it will yield the int
value 0
(meaning single-thread mode).
#define finally E4C_FINALLY |
Introduces a block of code responsible for cleaning up the previous exception-aware block
finally
blocks are optional code blocks that must be preceded by try
, with
... use
or using
blocks. It is allowed to place, at most, one finally
block for each one of these.
The finally
block can determine the completeness of the exception-aware block through the function e4c_get_status
. The thrown exception (if any) can also be accessed through the function e4c_get_exception
.
The finally block will be executed only once. The only possible way to execute it again would be by retry
ing the entire try
block.
finally
block must be preceded by a try
, with
... use
, using
or catch
block.finally
block must not be exited through any of: goto
, break
, continue
or return
(but it is legal to throw
an exception). finally
. Such programming error will lead to an abrupt exit of the program (or thread).#define reacquire | ( | max_reacquire_attempts | ) | E4C_REACQUIRE(max_reacquire_attempts) |
Repeats the previous with
block entirely
max_reacquire_attempts | The maximum number of attempts to reacquire |
This macro discards any thrown exception (if any) and repeats the previous with
block, up to a specified maximum number of attempts. If the acquisition completes, then the use
block will be executed.
It is intended to be used within catch
or finally
blocks, next to a with
... use
or using
block, when the resource acquisition fails, as a quick way to fix an error condition and try to acquire the resource again.
with
block can eventually be attempted an unlimited number of times. Care should be taken in order not to create an infinite loop.Once the resource has been acquired, the use
block can also be repeated alone through the keyword retry
:
reacquire
keyword must be used from a catch
or finally
block, preceded by with
... use
or using
blocks.reacquire
. Such programming error will lead to an abrupt exit of the program (or thread). with
block has already been attempted, at least, the specified maximum number of times.#define rethrow | ( | message | ) | E4C_RETHROW(message) |
Throws again the currently thrown exception, with a new message
message | The new message describing the exception. It should be more specific than the current one |
This macro creates a new instance of the thrown exception, with a more specific message.
rethrow
is intended to be used within a catch
block; the purpose is to refine the message of the currently caught exception. The previous exception (and its message) will be stored as the cause of the newly thrown exception.
The semantics of this keyword are the same as for throw
.
rethrow
. Such programming error will lead to an abrupt exit of the program (or thread). rethrow
point.#define retry | ( | max_retry_attempts | ) | E4C_RETRY(max_retry_attempts) |
Repeats the previous try
(or use
) block entirely
max_retry_attempts | The maximum number of attempts to retry |
This macro discards any thrown exception (if any) and repeats the previous try
or use
block, up to a specified maximum number of attempts. It is intended to be used within catch
or finally
blocks as a quick way to fix an error condition and try again.
If the block has already been tried at least the specified number of times, then the program continues by the next line following retry
clause.
This macro won't return control unless the block has already been attempted, at least, the specified maximum number of times.
catch
code block is being executed, the current exception is considered caught. If you want the exception to be propagated when the maximum number of attempts has been reached, then you need to rethrow
it.finally
block, the current exception (if any) will be propagated when the retry
does not take place, so you don't need to rethrow
it again.retry
. Such programming error will lead to an abrupt exit of the program (or thread).retry
keyword must be used from a catch
or finally
block. retry
point, unless the try
(or use
) block has already been attempted, at least, the specified number of times.#define throw | ( | exception_type, | |
message | |||
) | E4C_THROW(exception_type, message) |
Signals an exceptional situation represented by an exception object
exception_type | The type of exception to be thrown |
message | The ad-hoc message describing the exception. If NULL , then the default message for the specified exception type will be used |
Creates a new instance of the specified type of exception and then throws it. The message is copied into the thrown exception, so it may be freely deallocated. If NULL
is passed, then the default message for that type of exception will be used.
When an exception is thrown, the exception handling framework looks for the appropriate catch
block that can handle the exception. The system unwinds the call chain of the program and executes the finally
blocks it finds.
When no catch
block is able to handle an exception, the system eventually gets to the main function of the program. This situation is called an uncaught exception.
throw
. Such programming error will lead to an abrupt exit of the program (or thread). throw
point.#define try E4C_TRY |
Introduces a block of code aware of exceptions
A try
statement executes a block of code. If an exception is thrown and there is a catch
block that can handle it, then control will be transferred to it. If there is a finally
block, then it will be executed, no matter whether the try
block completes normally or abruptly, and no matter whether a catch
block is first given control.
The block of code immediately after the keyword try
is called the try
block of the try
statement. The block of code immediately after the keyword finally
is called the finally
block of the try
statement.
One try
block may precede many catch
blocks (also called exception handlers). A catch
block must have exactly one parameter, which is the exception type it is capable of handling. Within the catch
block, the exception can be accessed through the function e4c_get_exception
. Exception handlers are considered in left-to-right order: the earliest possible catch
block handles the exception. If no catch
block can handle the thrown exception, it will be propagated.
Sometimes it may come in handy to retry
an entire try
block; for instance, once the exception has been caught and the error condition has been solved.
A try
block has an associated status according to the way it has been executed:
catch
block handles it.The status of the current try
block can be retrieved through the function e4c_get_status
.
try
. Such programming error will lead to an abrupt exit of the program (or thread).try
block must precede, at least, another block of code, introduced by either catch
or finally
.try
block may precede several catch
blocks.try
block can precede, at most, one finally
block.try
block must not be exited through any of: goto
, break
, continue
or return
(but it is legal to throw
an exception).finally
block will be executed after the try
block and any catch
block that might be executed, no matter whether the try
block succeeds, recovers or fails.#define use E4C_USE |
Closes a block of code with automatic disposal of a resource
A use
block must always be preceded by a with
block. These two keywords are designed so the compiler will complain about dangling with
... use
blocks.
A code block introduced by the use
keyword will only be executed if, and only if, the acquisition of the resource completes without exceptions.
The disposal function will be executed, either if the use
block completes or not.
use
block must be preceded by a with
block.use
block must not be exited through any of: goto
, break
, continue
or return
(but it is legal to throw
an exception).#define using | ( | type, | |
resource, | |||
args | |||
) | E4C_USING(type, resource, args) |
Introduces a block of code with automatic acquisition and disposal of a resource
type | The type of the resource |
resource | The resource to be acquired, used and then disposed |
args | A list of arguments to be passed to the acquisition function |
The specified resource will be acquired, used and then disposed. The automatic acquisition and disposal is achieved by calling the implicit functions e4c_acquire_type and e4c_dispose_type:
TYPE e4c_acquire_TYPE(ARGS)
void e4c_dispose_TYPE(TYPE RESOURCE, E4C_BOOL failed)
These two symbols must exist, in the form of either functions or macros.
The semantics of the automatic acquisition and disposal are the same as for blocks introduced by with
... use
. For example, a using
block can also precede catch
and finally
blocks.
using
. Such programming error will lead to an abrupt exit of the program (or thread).using
block must not be exited through any of: goto
, break
, continue
or return
(but it is legal to throw
an exception).#define with | ( | resource, | |
dispose | |||
) | E4C_WITH(resource, dispose) |
Opens a block of code with automatic disposal of a resource
resource | The resource to be disposed |
dispose | The name of the disposal function (or macro) |
The combination of keywords with
... use
encapsules the Dispose Pattern. This pattern consists of two separate blocks and an implicit call to a given function:
with
block is responsible for the resource acquisitionuse
block makes use of the resourceA with
block must be followed by a use
block. In addition, the use
block may be followed by several catch
blocks and/or one finally
block.
The with
keyword guarantees that the disposal function will be called if, and only if, the acquisition block is completed without any errors (i.e. the acquisition block does not throw
any exceptions).
If the with
block does not complete, neither the disposal function nor the use
block will be executed.
The disposal function is called right after the use
block. If an exception is thrown, the catch
or finally
blocks (if any) will take place after the disposal of the resource.
When called, the disposal function will receive two arguments:
use
block failed (i. e. did not complete)This way, different actions can be taken depending on the success or failure of the block. For example, commiting or rolling back a transaction resource.
Legacy functions can be reused by defining macros. For example, a file resource needs to be closed regardless of the errors occurred. Since the function fclose
only takes one parameter, we could define the next macro:
Here is the typical usage of with
... use
:
Nonetheless, one-liners fit nicely too:
There is a way to lighten up even more this pattern by defining convenience macros, customized for a specific kind of resources. For example, #e4c_using_file
or #e4c_using_memory
.
with
. Such programming error will lead to an abrupt exit of the program (or thread).with
block must not be exited through any of: goto
, break
, continue
or return
(but it is legal to throw
an exception).with
block must always be followed by a use
block.typedef void(* e4c_finalize_handler) (void *custom_data) |
Represents a function which will be executed whenever an exception is destroyed.
custom_data | The "custom data" of the exception to be discarded |
When this handler is set, it will be called any time an exception is discarded. It will be passed the custom_data of the exception, so it may dispose resources previously acquired by the initialize handler.
This handler can be set through the function e4c_context_set_handlers
:
typedef void*(* e4c_initialize_handler) (const e4c_exception *exception) |
Represents a function which will be executed whenever a new exception is thrown.
exception | The newly thrown exception |
When this handler is set, it will be called any time a new exception is created. The void
pointer returned by this function will be assigned to the exception's custom_data. This data can be accessed later on, for example, from a catch
block, or an uncaught handler, for any specific purpose.
This handler can be set through the function e4c_context_set_handlers
:
By the time this handler is called, the exception already has been assigned the initial value specified for custom_data
, so the handler may make use of it:
typedef void(* e4c_uncaught_handler) (const e4c_exception *exception) |
Represents a function which will be executed in the event of an uncaught exception.
exception | The uncaught exception |
This handler can be set through the function e4c_context_set_handlers
:
There exists a convenience function e4c_print_exception
which is used as the default uncaught handler, unless otherwise specified. It simply prints information regarding the exception to stderr
.
enum e4c_status_ |
Represents the completeness of a code block aware of exceptions
The symbolic values representing the status of a block help to distinguish between different possible situations inside a finally
block. For example, different cleanup actions can be taken, depending on the status of the block.
Enumerator | |
---|---|
e4c_succeeded |
There were no exceptions |
e4c_recovered |
There was an exception, but it was caught |
e4c_failed |
There was an exception and it wasn't caught |
void e4c_context_begin | ( | E4C_BOOL | handle_signals | ) |
Begins an exception context
handle_signals | If true , the signal handling system will be set up with the default mapping. |
This function begins the current exception context to be used by the program (or current thread), until e4c_context_end
is called.
The signal handling system can be initialized automatically with the default signal mappings by passing handle_signals=true
. This is equivalent to:
signal
function might be undefined for a multithreaded program, so use the signal handling system with caution.The convenience function e4c_print_exception
will be used as the default uncaught handler. It will be called in the event of an uncaught exception, before exiting the program or thread. This handler can be set through the function e4c_context_set_handlers
.
e4c_context_begin
is called, the program (or thread) must call e4c_context_end
before exiting.e4c_context_begin
twice in a row is considered a programming error, and therefore the program (or thread) will exit abruptly. Nevertheless, e4c_context_begin
can be called several times if, and only if, e4c_context_end
is called in between.void e4c_context_end | ( | void | ) |
Ends the current exception context
This function ends the current exception context.
e4c_context_end
. Such programming error will lead to an abrupt exit of the program (or thread).const e4c_signal_mapping* e4c_context_get_signal_mappings | ( | void | ) |
Retrieves the signal mappings for the current exception context
This function retrieves the current array of mappings between the signals to be handled and the corresponding exception to be thrown.
e4c_context_get_signal_mappings
. Such programming error will lead to an abrupt exit of the program (or thread).E4C_BOOL e4c_context_is_ready | ( | void | ) |
Checks if the current exception context is ready
This function returns whether there is an actual exception context ready to be used by the program or current thread.
void e4c_context_set_handlers | ( | e4c_uncaught_handler | uncaught_handler, |
void * | custom_data, | ||
e4c_initialize_handler | initialize_handler, | ||
e4c_finalize_handler | finalize_handler | ||
) |
Sets the optional handlers of an exception context
uncaught_handler | The function to be executed in the event of an uncaught exception |
custom_data | The initial value assigned to the custom_data of a new exception |
initialize_handler | The function to be executed whenever a new exception is thrown |
finalize_handler | The function to be executed whenever an exception is destroyed |
These handlers are a means of customizing the behavior of the exception system. For example, you can specify what needs to be done when a thrown exception is not caught (and thus, the program or thread is about to end) by calling e4c_context_set_handlers
with your own uncaught handler.
You can also control the custom data attached to any new exception by specifying any or all of these:
custom_data
custom_data
custom_data
When these handlers are defined, they will be called anytime an exception is uncaught, created or destroyed. You can use them to meet your specific needs. For example, you could...
e4c_context_set_handlers
. Such programming error will lead to an abrupt exit of the program (or thread).void e4c_context_set_signal_mappings | ( | const e4c_signal_mapping * | mappings | ) |
Assigns the specified signal mappings to the exception context
mappings | The array of mappings |
This function assigns an array of mappings between the signals to be handled and the corresponding exception to be thrown.
signal
function might be undefined for a multithreaded program, so use the signal handling system with caution.e4c_context_set_signal_mappings
. Such programming error will lead to an abrupt exit of the program (or thread).mappings
must be terminated by E4C_NULL_SIGNAL_MAPPING
.E4C_DECLARE_EXCEPTION | ( | RuntimeException | ) |
This is the root of the exception pseudo-hierarchy
#RuntimeException
is the common supertype of all exceptions.
E4C_DECLARE_EXCEPTION | ( | NotEnoughMemoryException | ) |
This exception is thrown when the system runs out of memory
#NotEnoughMemoryException
is thrown when there is not enough memory to continue the execution of the program.
E4C_DECLARE_EXCEPTION | ( | IllegalArgumentException | ) |
This exception is thrown when a function is passed an illegal or inappropriate argument
#IllegalArgumentException
is thrown by a function when it detects that some of the function parameters (passed by the caller) is unacceptable.
E4C_DECLARE_EXCEPTION | ( | AssertionException | ) |
This exception is thrown when an assertion does not hold
#AssertionException
is part of the assertion facility of the library. It is thrown when the compile-time parameter NDEBUG
is present and the conditon of an assertion evaluates to false
.
finally
blocks.E4C_DECLARE_EXCEPTION | ( | InputOutputException | ) |
This exception is thrown when an input/output error occurs
#InputOutputException
is the general type of exceptions produced by failed or interrupted I/O operations.
E4C_DECLARE_EXCEPTION | ( | SignalException | ) |
This exception is the common supertype of all signal exceptions
Signal exceptions are thrown when some signal is sent to the process.
A signal can be generated by calling raise
.
E4C_DECLARE_EXCEPTION | ( | SignalAlarmException | ) |
This exception is thrown when a time limit has elapsed
#SignalAlarmException
represents SIGALRM
, the signal sent to a process when a time limit has elapsed.
E4C_DECLARE_EXCEPTION | ( | SignalChildException | ) |
This exception is thrown when a child process terminates
#SignalChildException
represents SIGCHLD
, the signal sent to a process when a child process terminates.
E4C_DECLARE_EXCEPTION | ( | SignalTrapException | ) |
This exception is thrown when a condition arises that a debugger has requested to be informed of
#SignalTrapException
represents SIGTRAP
, the signal sent to a process when a condition arises that a debugger has requested to be informed of.
E4C_DECLARE_EXCEPTION | ( | ErrorSignalException | ) |
This exception is the common supertype of all error signal exceptions
Error signal exceptions are thrown when some error prevents the program to keep executing its normal flow.
E4C_DECLARE_EXCEPTION | ( | IllegalInstructionException | ) |
This exception is thrown when the process attempts to execute an illegal instruction
#IllegalInstructionException
represents SIGILL
, the signal sent to a process when it attempts to execute a malformed, unknown, or privileged instruction.
E4C_DECLARE_EXCEPTION | ( | ArithmeticException | ) |
This exception is thrown when the process performs an erroneous arithmetic operation
#ArithmeticException
represents SIGFPE
, the signal sent to a process when it performs an erroneous arithmetic operation.
E4C_DECLARE_EXCEPTION | ( | BrokenPipeException | ) |
This exception is thrown when the process attempts to write to a broken pipe
#BrokenPipeException
represents SIGPIPE
, the signal sent to a process when it attempts to write to a pipe without a process connected to the other end.
E4C_DECLARE_EXCEPTION | ( | BadPointerException | ) |
This exception is thrown when the process tries to dereference an invalid pointer
#BadPointerException
represents SIGSEGV
, the signal sent to a process when it makes an invalid memory reference, or segmentation fault.
E4C_DECLARE_EXCEPTION | ( | NullPointerException | ) |
This exception is thrown when an unexpected null pointer is found
#NullPointerException
is thrown when some part of the program gets a pointer which was expected or required to contain a valid memory address.
A null pointer exception is a special case of a bad pointer exception. The difference between them is that #NullPointerException
needs to be thrown explicitly by some function, while #BadPointerException
is thrown implicitly by the signal handling system (if enabled).
E4C_DECLARE_EXCEPTION | ( | ControlSignalException | ) |
This exception is the common supertype of all control signal exceptions
Control signal exceptions are thrown when the process needs to be controlled by the user or some other process.
E4C_DECLARE_EXCEPTION | ( | StopException | ) |
This exception is thrown to stop the process for later resumption
#StopException
represents SIGSTOP
, the signal sent to a process to stop it for later resumption.
SIGSTOP
is usually unblock-able, it won't be handled and converted to this exception automatically on some platforms.E4C_DECLARE_EXCEPTION | ( | KillException | ) |
This exception is thrown to terminate the process immediately
#KillException
represents SIGKILL
, the signal sent to a process to cause it to terminate immediately.
SIGKILL
is usually unblock-able, it won't be handled and converted to this exception automatically on some platforms.E4C_DECLARE_EXCEPTION | ( | HangUpException | ) |
This exception is thrown when the process' terminal is closed
#HangUpException
represents SIGHUP
, the signal sent to a process when its controlling terminal is closed.
E4C_DECLARE_EXCEPTION | ( | TerminationException | ) |
This exception is thrown to request the termination of the process
#TerminationException
represents SIGTERM
, the signal sent to a process to request its termination.
E4C_DECLARE_EXCEPTION | ( | AbortException | ) |
This exception is thrown to abort the process
#AbortException
represents SIGABRT
, the signal sent by computer programs to abort the process.
E4C_DECLARE_EXCEPTION | ( | CPUTimeException | ) |
This exception is thrown when the process has used up the CPU for too long
#CPUTimeException
represents SIGXCPU
, the signal sent to a process when it has used up the CPU for a duration that exceeds a certain predetermined user-settable value.
E4C_DECLARE_EXCEPTION | ( | UserControlSignalException | ) |
This exception is the common supertype of all control signal exceptions caused by the user
User control signal exceptions are thrown when the process needs to be controlled by the user.
E4C_DECLARE_EXCEPTION | ( | UserQuitException | ) |
This exception is thrown when the user requests to quit the process
#UserQuitException
represents SIGQUIT
, the signal sent to a process by its controlling terminal when the user requests that the process dump core.
E4C_DECLARE_EXCEPTION | ( | UserInterruptionException | ) |
This exception is thrown when the user requests to interrupt the process
#UserInterruptionException
represents SIGINT
, the signal sent to a process by its controlling terminal when a user wishes to interrupt it.
E4C_DECLARE_EXCEPTION | ( | UserBreakException | ) |
This exception is thrown when a user wishes to break the process
#UserBreakException
represents SIGBREAK
, the signal sent to a process by its controlling terminal when a user wishes to break it.
E4C_DECLARE_EXCEPTION | ( | ProgramSignalException | ) |
This exception is the common supertype of all user-defined signal exceptions
User-defined signal exceptions are thrown to indicate user-defined conditions.
E4C_DECLARE_EXCEPTION | ( | ProgramSignal1Exception | ) |
This exception is thrown when user-defined conditions occur
#ProgramSignal1Exception
represents SIGUSR1
, the signal sent to a process to indicate user-defined conditions.
E4C_DECLARE_EXCEPTION | ( | ProgramSignal2Exception | ) |
This exception is thrown when user-defined conditions occur
#ProgramSignal2Exception
represents SIGUSR1
, the signal sent to a process to indicate user-defined conditions.
const e4c_exception* e4c_get_exception | ( | void | ) |
Returns the exception that was thrown
NULL
This function returns a pointer to the exception that was thrown in the surrounding exception-aware block, if any; otherwise NULL
.
The function e4c_is_instance_of
will determine if the thrown exception is an instance of any of the defined exception types. The type
of the thrown exception can also be compared for an exact type match.
The thrown exception can be obtained any time, provided that the exception context has begun at the time of the function call. However, it is sensible to call this function only during the execution of finally
or catch
blocks.
Moreover, a pointer to the thrown exception obtained inside a finally
or catch
block must not be used outside these blocks.
The exception system objects are dinamically allocated and deallocated, as the program enters or exits try
... catch
... finally
blocks. While it would be legal to copy the thrown exception and access to its name
and message
outside these blocks, care should be taken in order not to dereference the cause
of the exception, unless it is a deep copy (as opposed to a shallow copy).
e4c_get_exception
. Such programming error will lead to an abrupt exit of the program (or thread).e4c_status e4c_get_status | ( | void | ) |
Returns the completeness status of the executing code block
Exception-aware code blocks have a completeness status regarding the exception handling system. This status determines whether an exception was actually thrown or not, and whether the exception was caught or not.
The status of the current block can be obtained any time, provided that the exception context has begun at the time of the function call. However, it is sensible to call this function only during the execution of finally
blocks.
e4c_get_status
. Such programming error will lead to an abrupt exit of the program (or thread).E4C_BOOL e4c_is_instance_of | ( | const e4c_exception * | instance, |
const e4c_exception_type * | exception_type | ||
) |
Returns whether an exception instance is of a given type
instance | The thrown exception |
exception_type | A previously defined type of exceptions |
e4c_is_instance_of
can be used to determine if a thrown exception is an instance of a given exception type.
This function is intended to be used in a catch
block, or in a finally
block provided that some exception was actually thrown (i.e. e4c_get_status
returs e4c_failed
or e4c_recovered
).
This function will return false
if either instance
or type
are NULL
.
instance
must not be NULL
type
must not be NULL
long e4c_library_version | ( | void | ) |
Gets the library version number
This function provides the same information as the E4C_VERSION_NUMBER
macro, but the returned version number is associated with the actual, compiled library.
void e4c_print_exception | ( | const e4c_exception * | exception | ) |
Prints a fatal error message regarding the specified exception
exception | The uncaught exception |
This is a convenience function for showing an error message through the standard error output. It can be passed to e4c_context_set_handlers
as the handler for uncaught exceptions. Will be used by default, unless otherwise set up.
In absence of NDEBUG
, this function prints as much information regarding the exception as it is available, whereas in presence of NDEBUG
, only the name
and message
of the exception are printed.
exception
must not be NULL
#NullPointerException | If exception is NULL |
void e4c_print_exception_type | ( | const e4c_exception_type * | exception_type | ) |
Prints an ASCII graph representing an exception type's hierarchy
exception_type | An exception type |
This is a convenience function for showing an ASCII graph representing an exception type's hierarchy through the standard error output.
For example, the output for #ProgramSignal2Exception
would be:
exception_type
must not be NULL
#NullPointerException | If exception_type is NULL |
const e4c_signal_mapping* const e4c_default_signal_mappings |
The array of predefined signal mappings.