# error.h ## Overview
Functions for error handling.
## Index
`tm_error_o`

`struct tm_error_i`
`inst`
`errorf()`
`fatal()`

`struct tm_error_record_t`
`TM_ERROR_API_NAME`

`struct tm_error_api`
`log`
`def`
`create_record_handler()`

`TM_ERROR()`
`TM_ASSERT()`
`TM_FATAL_ASSERT()`
`TM_FATAL_ASSERT_FORMAT()`
`TM_STATIC_ASSERT()`
`TM_NOT_YET_IMPLEMENTED()`
## API
### `tm_error_o`
~~~c typedef struct tm_error_o tm_error_o; ~~~
### `struct tm_error_i`
Interface for error handling. Application errors will be reported to this interface. It is up to the interface to decide how to deal with them. #### `inst` ~~~c tm_error_o *inst; ~~~ #### `errorf()` ~~~c void (*errorf)(tm_error_o *inst, const char *file, uint32_t line, const char *format, ...); ~~~ Reports an error at the specified `file` and `line` of the code. The error message should be a verbose enough description of the error that someone who reads the error message can diagnose and fix the problem. #### `fatal()` ~~~c void (*fatal)(tm_error_o *inst, const char *file, uint32_t line, const char *format, ...); ~~~ As `errorf()`, but used to report a fatal error. This is called whenever a "fatal" error occurs -- an error so serious that there is no possible way the engine can continue running. (When a normal error occur, the engine tries to keep running to give the user a chance to save their data.) `fatal()` is typically called by the `TM_FATAL_ASSERT()` macro. Note that this macro calls `errorf()` first, so `fatal()` does not have to repeat the logging that `errorf()` does, but it might want to show a more prominent error, such as an error dialog box, before shutting down the application. !!! TODO: API-REVIEW For consistency, this function should be called `fatalf()`.
### `struct tm_error_record_t`
Structure used by `tm_error_api->create_record_handler()` to record error messages. In addition to recording the errors in the `errors` array, this handler also passes them on to the `backing` error handler (if it is non-zero). ~~~c typedef struct tm_error_record_t { struct tm_temp_allocator_i *ta; /* carray */ char **errors; tm_error_i *backing; } tm_error_record_t; ~~~
### `TM_ERROR_API_NAME`
~~~c #define TM_ERROR_API_NAME "tm_error_api" ~~~
### `struct tm_error_api`
API for error handling. This API provides a number of default error handlers. !!! TIP In addition to the error handlers defined here, you can also create your own error handler. You can use this for example to implement a unit test that tests that a certain action produces an expected error. #### `log` ~~~c tm_error_i *log; ~~~ Basic error handler that just logs the error messages using `tm_logger_api->print()`. Fatal errors are shown in a dialog box using `tm_os_dialogs_api->message_box()`. #### `def` ~~~c tm_error_i *def; ~~~ Default error handler. This can be used by systems that for one reason or another don't want to take an explicit `tm_error_i` argument. Assign this value to change the default error handler. By default, this is mapped to the `log` error handler. !!! TODO: API-REVIEW Currently, a lot of system just use the default error handler. We should update them to expose the error handler as an argument, so that the caller can get detailed control over how errors are handled. #### `create_record_handler()` ~~~c tm_error_i (*create_record_handler)(tm_error_record_t *mem); ~~~ Creates an error handler that stores all the encountered error messages in the `mem` structure. In addition, it also passes along the errors to `mem->backing` (if non-zero).
### `TM_ERROR()`
~~~c #define TM_ERROR(ei, format, ...) ~~~ Macro that reports an error using `tm_error_i->errorf()`. Often called as `TM_ERROR(tm_error_api->def, msg);`.
### `TM_ASSERT()`
~~~c #define TM_ASSERT(test, ei, format, ...) ~~~ Macro that asserts that the `test` condition is *true*. If `test` evaluates to *false*, this function will call `tm_error_i->errorf()` with the `format, ...` parameters. The macro returns the result of the `test`. You can use this to take an appropriate action to proceed if the test fails, such as returning a default value, aborting the operation, etc.
### `TM_FATAL_ASSERT()`
~~~c #define TM_FATAL_ASSERT(test, ei) ~~~ As `TM_ASSERT()`, but reports a fatal assert by calling `errorf()` and `fatal()`. You should use this as a last resort in situations where there is no possible way for the application to continue in case of a failure. Otherwise, prefer `TM_ASSERT()` and try to recover from the error as best you can, we don't want to unnecessarily crash the user's application.
### `TM_FATAL_ASSERT_FORMAT()`
~~~c #define TM_FATAL_ASSERT_FORMAT(test, ei, format, ...) ~~~ As `TM_FATAL_ASSERT()` but prints a formatted error message. !!! TODO: API-REVIEW Replace `TM_FATAL_ASSERT()` with this one?
### `TM_STATIC_ASSERT()`
~~~c #define TM_STATIC_ASSERT(x) ~~~ A zero cost assert macro that is checked at compile time and produces a compile error if the assertion fails. Usually just used to check that the `sizeof()` some object is what you expect.
### `TM_NOT_YET_IMPLEMENTED()`
~~~c #define TM_NOT_YET_IMPLEMENTED(ei) ~~~ Used to mark a not yet implemented function of an API. This should only be used as a temporary error until the function can be implemented: ~~~c void my_function(void) { // TODO: Implement this. TM_NOT_YET_IMPLEMENTED(tm_error_api->def); } ~~~~