feature: add more error codes, and document error handling macros

This commit is contained in:
MechSlayer 2025-09-05 15:15:25 +02:00
parent 13cc25860e
commit d787477657
2 changed files with 107 additions and 14 deletions

View file

@ -10,32 +10,75 @@ DRANG_BEGIN_DECLS
*/
DRANG_API const char *drang_error_str(int err);
#define DRANG_EOK (0)
#define DRANG_EINVAL (-1)
#define DRANG_ENOMEM (-2)
#define DRANG_EIO (-3)
#define DRANG_NOTSUP (-4)
#define DRANG_EAGAIN (-5)
#define DRANG_ENOENT (-6)
#define DRANG_EOK (0) // Success
#define DRANG_EINVAL (-1) // Invalid argument
#define DRANG_ENOMEM (-2) // Out of memory
#define DRANG_EIO (-3) // I/O error
#define DRANG_NOTSUP (-4) // Operation not supported
#define DRANG_EAGAIN (-5) // Resource temporarily unavailable
#define DRANG_ENOENT (-6) // No such file or directory
#define DRANG_EDEADLK (-7) // Resource deadlock would occur
#define DRANG_EPERM (-8) // Operation not permitted
#define DRANG_ETIMEDOUT (-9) // Connection timed out
#define DRANG_EBUSY (-10) // Device or resource busy
/**
* @brief Begins a try-catch block for error handling.
* @details Initializes the error handling mechanism by declaring a local
* variable `_res` and starting a new scope. This macro must be
* paired with either DRANG_END_TRY() or DRANG_END_TRY_IGNORE().
* @remarks Use this macro at the beginning of a function that needs
* structured error handling. All error-prone operations should
* be wrapped with DRANG_TRY() or DRANG_CHECK().
*/
#define DRANG_BEGIN_TRY() \
int _res = DRANG_EOK; \
{
/**
* @brief Defines a catch block that executes when an error occurs.
* @param name Variable name to hold the error code in the catch block.
* @details This macro closes the try block and starts a catch block that
* only executes if an error occurred (_res != DRANG_EOK).
* @remarks The catch block is required and must be followed by DRANG_END_TRY().
* If no special handling is needed, use DRANG_END_TRY_IGNORE() instead.
*/
#define DRANG_CATCH(name) \
} \
_drang_cleanup: \
if (_res != DRANG_EOK) { \
int name = _res;
/**
* @brief Ends a try-catch block and returns the error code.
* @details Closes any open catch block and returns the current error status.
* If no error occurred, returns DRANG_EOK.
* @remarks This macro must be used to properly close a DRANG_BEGIN_TRY() block.
* The function will return the error code to the caller.
*/
#define DRANG_END_TRY() \
} \
return _res;
/**
* @brief Ends a try-catch block when no catch handling is needed.
* @details Similar to DRANG_END_TRY() but provides an empty cleanup label.
* @remarks Use this when you don't need to perform cleanup operations after
* error handling.
*/
#define DRANG_END_TRY_IGNORE() \
} \
_drang_cleanup: \
return _res;
/**
* @brief Executes an expression and jumps to clean up on error.
* @param expr Expression that returns a DRANG error code.
* @details Evaluates the given expression and stores the result in `_res`.
* If the result is not DRANG_EOK, immediately jumps to the cleanup
* section using goto.
* @remarks This macro should only be used within a DRANG_BEGIN_TRY()...DRANG_END_TRY()
* block. The expression should return a DRANG error code.
*/
#define DRANG_TRY(expr) \
do { \
_res = (expr); \
@ -44,6 +87,15 @@ DRANG_API const char *drang_error_str(int err);
} \
} while (0)
/**
* @brief Checks a condition and fails with specified error if false.
* @param expr Boolean expression to evaluate.
* @param err Error code to set if the expression is false.
* @details If the expression evaluates to false, sets `_res` to the specified
* error code and jumps to the cleanup section.
* @remarks Use this for validating preconditions, parameter checks, or any
* boolean conditions that should cause the function to fail.
*/
#define DRANG_CHECK(expr, err) \
do { \
if (!(expr)) { \
@ -52,18 +104,52 @@ DRANG_API const char *drang_error_str(int err);
} \
} while (0)
/**
* @brief Immediately fails with the specified error code.
* @param err Error code to set before jumping to clean up.
* @details Sets `_res` to the specified error code and immediately jumps
* to the cleanup section without any condition checking.
* @remarks Use this when you need to unconditionally fail and exit the
* current function with a specific error code.
*/
#define DRANG_FAIL(err) \
_res = (err); \
goto _drang_cleanup
/**
* @brief Successfully returns a value through an output parameter.
* @param _Out_Ptr_ Pointer to the output parameter.
* @param _Value_ Value to assign to the output parameter.
* @details Sets the output parameter to the specified value, marks the
* operation as successful (DRANG_EOK), and jumps to clean up.
* @remarks Use this macro when you need to return a value through a pointer
* parameter and ensure proper cleanup before function exit.
*/
#define DRANG_RETURN_IN(_Out_Ptr_, _Value_) \
_res = DRANG_EOK; \
(*(_Out_Ptr_) = (_Value_)); \
goto _drang_cleanup
/**
* @brief Successfully completes the operation and jumps to cleanup.
* @details Sets `_res` to DRANG_EOK and jumps to the cleanup section,
* indicating successful completion of the operation.
* @remarks Use this when you need to exit successfully from the middle
* of a function while ensuring proper cleanup is performed.
*/
#define DRANG_RETURN() \
_res = DRANG_EOK; \
goto _drang_cleanup
/**
* @brief Checks if a pointer is NULL and fails with specified error.
* @param ptr Pointer to check for NULL.
* @param err Error code to set if the pointer is NULL.
* @details If the pointer is NULL, sets `_res` to the specified error
* code and jumps to the cleanup section.
* @remarks Use this for validating pointer parameters or return values
* from functions that might return NULL on failure.
*/
#define DRANG_FAIL_IF_NULL(ptr, err) \
do { \
if ((ptr) == NULL) { \
@ -72,12 +158,15 @@ DRANG_API const char *drang_error_str(int err);
} \
} while (0)
#define DRANG_FAIL_IF_NULL_OOM(ptr) \
do { \
if ((ptr) == NULL) { \
_res = DRANG_ENOMEM; \
goto _drang_cleanup; \
} \
} while (0)
/**
* @brief Checks if a pointer is NULL and fails with out-of-memory error.
* @param ptr Pointer to check for NULL.
* @details If the pointer is NULL, sets `_res` to DRANG_ENOMEM and jumps
* to the cleanup section. This is a convenience macro for memory
* allocation failure checks.
* @remarks Use this specifically after memory allocation operations where
* NULL indicates out-of-memory condition.
*/
#define DRANG_FAIL_IF_NULL_OOM(ptr) DRANG_FAIL_IF_NULL(ptr, DRANG_ENOMEM)
DRANG_END_DECLS

View file

@ -10,6 +10,10 @@ const char *drang_error_str(const int err)
case DRANG_NOTSUP: return "Operation not supported";
case DRANG_EAGAIN: return "Resource temporarily unavailable";
case DRANG_ENOENT: return "No such file or directory";
case DRANG_EDEADLK: return "Resource deadlock would occur";
case DRANG_EPERM: return "Operation not permitted";
case DRANG_ETIMEDOUT: return "Connection timed out";
case DRANG_EBUSY: return "Device or resource busy";
default: return "Unknown error";
}
}