Files
first/io.h
Krzosa Karol 11e6559a3c Init core
2023-12-31 07:44:32 +01:00

298 lines
7.7 KiB
C

#ifndef IO_HEADER
#define IO_HEADER
#include <stdbool.h>
typedef enum IO_ErrorResult IO_ErrorResult;
#ifndef IO_API
#ifdef __cplusplus
#define IO_API extern "C"
#else
#define IO_API
#endif
#endif
enum IO_ErrorResult {
IO_ErrorResult_Continue,
IO_ErrorResult_Break,
IO_ErrorResult_Exit,
};
#ifdef _WIN32
#define IO_DebugBreak() (__debugbreak(), 0)
#else
#define IO_DebugBreak() (IO_Exit(1), 0)
#endif
extern void (*IO_User_OutputMessage)(char *str, int len);
#define IO__STRINGIFY(x) #x
#define IO__TOSTRING(x) IO__STRINGIFY(x)
#define IO_LINE IO__TOSTRING(__LINE__)
#define IO_Assert(x) !(x) && IO__FatalError((char *)(__FILE__ "(" IO_LINE "): " \
"error: " #x "\n")) && \
IO_DebugBreak()
#define IO_FatalErrorf(...) \
do { \
bool result = IO__FatalErrorf(__FILE__, __LINE__, __VA_ARGS__); \
if (result) IO_DebugBreak(); \
} while (0)
#define IO_FatalError(...) \
do { \
bool result = IO__FatalError(__FILE__ "(" IO_LINE "): error - " __VA_ARGS__); \
if (result) IO_DebugBreak(); \
} while (0)
#define IO_Assertf(x, ...) \
do { \
if (!(x)) { \
bool result = IO__FatalErrorf(__FILE__, __LINE__, __VA_ARGS__); \
if (result) IO_DebugBreak(); \
} \
} while (0)
#define IO_InvalidElseIf(c) \
else if (c) { \
IO_InvalidCodepath(); \
}
#define IO_InvalidElse() \
else { \
IO_InvalidCodepath(); \
}
#define IO_InvalidCodepath() IO_FatalError("This codepath is invalid")
#define IO_InvalidDefaultCase() \
default: { \
IO_FatalError("Entered invalid switch statement case"); \
}
#define IO_Todo() IO_FatalError("This codepath is not implemented yet")
IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...);
IO_API void IO_Printf(const char *msg, ...);
IO_API bool IO__FatalError(char *msg);
IO_API void IO_Print(char *msg);
IO_API void IO_OutputMessage(char *str, int len);
IO_API IO_ErrorResult IO_OutputError(char *str, int len);
IO_API void IO_Exit(int error_code);
IO_API bool IO_IsDebuggerPresent(void);
#endif
#ifdef IO_IMPLEMENTATION
#ifndef IO_SNPRINTF
#include <stdio.h>
#define IO_SNPRINTF snprintf
#endif
#ifndef IO_VSNPRINTF
#include <stdio.h>
#define IO_VSNPRINTF vsnprintf
#endif
#ifndef IO_ALLOCATE
#include <stdlib.h>
#define IO_ALLOCATE(x) malloc(x)
#define IO_FREE(x) free(x)
#endif
#ifndef IO_FN
#if defined(__GNUC__) || defined(__clang__)
#define IO_FN __attribute__((unused)) static
#else
#define IO_FN static
#endif
#endif
IO_FN int IO_Strlen(char *string) {
int len = 0;
while (*string++ != 0) len++;
return len;
}
void (*IO_User_OutputMessage)(char *str, int len);
IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...) {
va_list args1;
va_list args2;
char buff[2048];
va_start(args1, msg);
va_copy(args2, args1);
int size = IO_VSNPRINTF(buff, sizeof(buff), msg, args2);
va_end(args2);
char *new_buffer = 0;
char *user_message = buff;
if (size >= sizeof(buff)) {
size += 4;
new_buffer = (char *)IO_ALLOCATE(size);
IO_VSNPRINTF(new_buffer, size, msg, args1);
user_message = new_buffer;
}
va_end(args1);
IO_ErrorResult ret = IO_ErrorResult_Continue;
{
char buff2[2048];
char *result = buff2;
char *b = 0;
int size = IO_SNPRINTF(buff2, sizeof(buff2), "%s(%d): error: %s \n", file, line, user_message);
if (size >= sizeof(buff2)) {
size += 4;
b = (char *)IO_ALLOCATE(size);
size = IO_SNPRINTF(b, size, "%s(%d): error: %s \n", file, line, user_message);
result = b;
}
ret = IO_OutputError(result, size);
if (ret == IO_ErrorResult_Exit) {
IO_Exit(1);
}
if (b) {
IO_FREE(b);
}
}
if (new_buffer) {
IO_FREE(new_buffer);
}
return ret == IO_ErrorResult_Break;
}
IO_API void IO_Printf(const char *msg, ...) {
va_list args1;
va_list args2;
char buff[2048];
va_start(args1, msg);
va_copy(args2, args1);
int size = IO_VSNPRINTF(buff, sizeof(buff), msg, args2);
va_end(args2);
char *new_buffer = 0;
char *result = buff;
if (size >= sizeof(buff)) {
size += 4;
new_buffer = (char *)IO_ALLOCATE(size);
IO_VSNPRINTF(new_buffer, size, msg, args1);
result = new_buffer;
}
va_end(args1);
if (IO_User_OutputMessage) {
IO_User_OutputMessage(result, size);
}
else {
IO_OutputMessage(result, size);
}
if (new_buffer) {
IO_FREE(new_buffer);
}
}
IO_API bool IO__FatalError(char *msg) {
int len = IO_Strlen(msg);
IO_ErrorResult result = IO_OutputError(msg, len);
if (result == IO_ErrorResult_Exit) {
IO_Exit(1);
}
return result == IO_ErrorResult_Break;
}
IO_API void IO_Print(char *msg) {
int len = IO_Strlen(msg);
if (IO_User_OutputMessage) {
IO_User_OutputMessage(msg, len);
}
else {
IO_OutputMessage(msg, len);
}
}
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#pragma comment(lib, "user32")
#include <stdio.h>
IO_API bool IO_IsDebuggerPresent(void) {
return IsDebuggerPresent();
}
IO_API void IO_OutputMessage(char *str, int len) {
if (IsDebuggerPresent()) {
OutputDebugStringA(str);
}
printf("%.*s", len, str);
fflush(stdout);
}
IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
IO_ErrorResult result = IO_ErrorResult_Continue;
IO_OutputMessage(str, len);
char *msg = str;
if (str[len] != 0) {
msg = (char *)IO_ALLOCATE(len + 1);
for (int i = 0; i < len; i += 1) msg[i] = str[i];
msg[len] = 0;
}
OutputDebugStringA(msg);
if (!IsDebuggerPresent()) {
// Limit size of error output message
char tmp = 0;
if (len > 4096) {
tmp = str[4096];
str[4096] = 0;
}
MessageBoxA(0, msg, "Error!", 0);
if (tmp != 0) {
str[4096] = tmp;
}
result = IO_ErrorResult_Exit;
}
else {
result = IO_ErrorResult_Break;
}
if (msg != str) {
IO_FREE(msg);
}
return result;
}
IO_API void IO_Exit(int error_code) {
ExitProcess(error_code);
}
#else // _WIN32 else // LIBC
#include <stdio.h>
IO_API IO_ErrorResult IO_OutputError(char *str, int len) {
fprintf(stderr, "%.*s", len, str);
return IO_ErrorResult_Exit;
}
IO_API void IO_OutputMessage(char *str, int len) {
fprintf(stdout, "%.*s", len, str);
}
IO_API void IO_Exit(int error_code) {
exit(error_code);
}
IO_API bool IO_IsDebuggerPresent(void) {
return false;
}
#endif // LIBC
#endif // IO_IMPLEMENTATION