diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..b180d93 --- /dev/null +++ b/src/error.c @@ -0,0 +1,71 @@ +#include "error.h" + +#include +#include +#include +#include +#include + +#define PRINT_BUFFER_SIZE 128 // defines the buffer size for printing + +// writes the arguments to the specified buffer +// using a macro instead of an inline function because fmt otherwise gets horribly messed up +#define write_args(buf, fmt) \ + va_list args; \ + va_start(args, fmt); \ + (void)vsnprintf(buf, PRINT_BUFFER_SIZE, fmt, args); \ + va_end(args); + +static gamestatus status = STATUS_RUNNING; + +void set_gamestatus(gamestatus nstatus) { + status = nstatus; +} + +gamestatus get_gamestatus(void) { + return status; +} + +void debug(char const* fmt, ...) { + char const* env = getenv("DEBUG"); + if (env == NULL || *env != '1') + return; + + char buf[PRINT_BUFFER_SIZE] = {0}; + write_args(buf, fmt); + + (void)fprintf(stdout, "\033[95m%s\033[0m\n", buf); +} + +void info(char const* fmt, ...) { + char buf[PRINT_BUFFER_SIZE] = {0}; + write_args(buf, fmt); + (void)fprintf(stdout, "\033[0m%s\033[0m\n", buf); // write colour here for consistency +} + +void warn(char const* fmt, ...) { + char buf[PRINT_BUFFER_SIZE] = {0}; + write_args(buf, fmt); + (void)fprintf(stderr, "\033[93mW: %s\033[0m\n", buf); +} + +void error(char const* fmt, ...) { + char buf[PRINT_BUFFER_SIZE] = {0}; + write_args(buf, fmt); + (void)fprintf(stderr, "\033[mW: %s\033[0m", buf); +} + +noreturn void fatal(gamestatus error_code, char const* fname, uint32_t ln, char const* fmt, ...) { + char buf1[PRINT_BUFFER_SIZE] = {0}; + write_args(buf1, fmt); + + char buf2[PRINT_BUFFER_SIZE * 2] = {0}; + sprintf(buf2, "%s\n at %s:%u (exitcode: %u)", buf1, fname, ln, error_code); + + (void)fprintf(stderr, "\033[91mE: %s\033[0m\n", buf2); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "something went wrong! :O", buf2, NULL); + + // set status, but exit immediately, as code is not allowed to execute beyond this point + set_gamestatus(error_code); + exit(status); +} diff --git a/src/error.h b/src/error.h new file mode 100644 index 0000000..e19d500 --- /dev/null +++ b/src/error.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +/* defines statuses in the 0..127, any higher/negative values are POSIX-reserved. + * The max value (or -1) shall mean the application is running, anything else shall mean an exit code of some kind */ +enum { + // clang-format off + STATUS_SUCCESS = 0, // 0; successful exit + STATUS_ERROR = 1, // miscellaneous error + ERROR_INIT = STATUS_ERROR | 2, // initialisation error + + ERROR_STD = STATUS_ERROR | 64, // standard library error + ERROR_STD_INIT = ERROR_INIT | 64, // standard library initialisation error + ERROR_STD_MEMORY = ERROR_STD | 32, // memory error + ERROR_STD_MEMORY_INIT = ERROR_STD_INIT | 32, // memory initialization error + + ERROR_SDL = STATUS_ERROR | 32, // SDL error + ERROR_SDL_INIT = ERROR_INIT | 32, // SDL initialization error + ERROR_SDL_RENDERING = ERROR_SDL | 16, // rendering error + ERROR_SDL_RENDERING_INIT = ERROR_SDL_INIT | 16, // rendering initialization error + ERROR_SDL_AUDIO = ERROR_SDL | 8, // audio error + ERROR_SDL_AUDIO_INIT = ERROR_SDL_INIT | 8, // audio initialization error + + STATUS_RUNNING = -1, + // clang-format on +}; +typedef int8_t gamestatus; + +void set_gamestatus(gamestatus); // sets the current status of the game +gamestatus get_gamestatus(void); // gets the current status of the game +void debug(char const*, ...); // prints a debug message to stdout if the DEBUG environment variable is set, otherwise the call is ignored. +void info(char const*, ...); // prints an info message to stdout +void warn(char const*, ...); // prints a warning message to stderr +void error(char const*, ...); // prints an warning message to stderr + +// prints an error message to stderr before exiting +noreturn void fatal(gamestatus, char const* file_name, uint32_t line, char const* fmt, ...);