/** * Copyright (c) 2025 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "assert/assert.h" #include "error.h" #include "util/memory.h" #include "util/string.h" errorret_t errorThrowImpl( errorstate_t *state, errorcode_t code, const char_t *file, const char_t *function, const int32_t line, const char_t *message, ... ) { assertNotNull(state, "Error state cannot be NULL"); assertTrue(code != ERROR_OK, "Error code must not be OK"); assertNotNull(file, "File cannot be NULL"); assertNotNull(function, "Function cannot be NULL"); assertTrue(line >= 0, "File pointer must be valid"); assertNotNull(message, "Message cannot be NULL"); memoryZero(state, sizeof(errorstate_t)); state->code = code; // Format args. va_list args; va_start(args, message); // Get length of formatted message va_list argsCopy; va_copy(argsCopy, args); int32_t len = stringFormatVA(NULL, 0, message, argsCopy); va_end(argsCopy); // Create string to hold the formatted message state->message = (char_t *)memoryAllocate(len + 1); stringFormatVA(state->message, len + 1, message, args); va_end(args); // Format lines len = stringFormat(NULL, 0, ERROR_LINE_FORMAT, file, line, function); assertTrue(len >= 0, "Line formatting failed"); state->lines = (char_t *)memoryAllocate(len + 1); stringFormat(state->lines, len + 1, ERROR_LINE_FORMAT, file, line, function); return (errorret_t) { .code = code, .state = state }; } errorret_t errorOkImpl() { assertTrue( ERROR_STATE.code == ERROR_OK, "Global error state is not OK (Likely missing errorCatch)" ); return (errorret_t) { .code = ERROR_OK, .state = NULL }; } errorret_t errorChainImpl( const errorret_t retval, const char_t *file, const char_t *function, const int32_t line ) { if (retval.code == ERROR_OK) return retval; assertNotNull(retval.state, "Error state NULL (Likely missing errorOk)"); assertNotNull(retval.state->message, "Message cannot be NULL"); // Create a new line string. int32_t newLineLen = snprintf(NULL, 0, ERROR_LINE_FORMAT, file, line, function); assertTrue(newLineLen >= 0, "Line formatting failed"); char_t *newLine = (char_t *)memoryAllocate(newLineLen + 1); snprintf(newLine, newLineLen + 1, ERROR_LINE_FORMAT, file, line, function); // Resize the existing lines to accommodate the new line size_t existingLen = strlen(retval.state->lines); memoryResize( (void**)&retval.state->lines, existingLen, existingLen + newLineLen + 1 ); // Now append the new line to the existing lines memoryCopy( retval.state->lines + existingLen, newLine, newLineLen + 1 ); // Cleanup the temporary new line memoryFree(newLine); return retval; } void errorCatch(const errorret_t retval) { if (retval.code == ERROR_OK) return; assertNotNull(retval.state, "Error state cannot be NULL"); assertNotNull(retval.state->message, "Message cannot be NULL"); memoryFree((void*)retval.state->message); } errorret_t errorPrint(const errorret_t retval) { if (retval.code == ERROR_OK) return retval; assertNotNull(retval.state, "Error state cannot be NULL"); assertNotNull(retval.state->message, "Message cannot be NULL"); printf( ERROR_PRINT_FORMAT, retval.state->code, retval.state->message, retval.state->lines ); return retval; }