diff --git a/storm/Error.cpp b/storm/Error.cpp index 76e47868..1f604003 100644 --- a/storm/Error.cpp +++ b/storm/Error.cpp @@ -1,24 +1,58 @@ #include "storm/Error.hpp" +#include "storm/thread/SCritSect.hpp" #include #include #include #if defined(WHOA_SYSTEM_WIN) #include +#define StormGetThreadId() GetCurrentThreadId() +#else +#include +#define StormGetThreadId() getpid() #endif +struct APPFATINFO { + const char* filename; + int32_t linenumber; + uint32_t threadId; +}; + +static APPFATINFO s_appFatInfo; + +SCritSect s_critsect; + static uint32_t s_lasterror = ERROR_SUCCESS; static int32_t s_suppress; static int32_t s_displaying; +[[noreturn]] void SErrDisplayAppFatalCustomV(uint32_t errorcode, const char* format, va_list va) { + const char* filename = nullptr; + int32_t linenumber = 0; + s_critsect.Enter(); + if (s_appFatInfo.threadId == StormGetThreadId()) { + filename = s_appFatInfo.filename; + linenumber = s_appFatInfo.linenumber; + s_appFatInfo = {}; + } + s_critsect.Leave(); + + char buffer[2048]; + std::vsnprintf(buffer, sizeof(buffer) - 1, format, va); + buffer[sizeof(buffer) - 1] = '\0'; + +#ifdef WHOA_DISPLAY_ERR_EXTRA_ARG + SErrDisplayError(errorcode, filename, linenumber, buffer, 0, EXIT_FAILURE, 2); +#else + SErrDisplayError(errorcode, filename, linenumber, buffer, 0, EXIT_FAILURE); +#endif + std::exit(EXIT_FAILURE); +} + [[noreturn]] void STORMCDECL SErrDisplayAppFatal(const char* format, ...) { va_list args; va_start(args, format); - vprintf(format, args); - printf("\n"); - va_end(args); - - exit(EXIT_FAILURE); + SErrDisplayAppFatalCustomV(STORM_ERROR_FATAL_CONDITION, format, args); } #ifdef WHOA_DISPLAY_ERR_EXTRA_ARG @@ -81,12 +115,35 @@ int32_t STORMCDECL SErrDisplayErrorFmt(uint32_t errorcode, const char* filename, return SErrDisplayError(errorcode, filename, linenumber, buffer, recoverable, exitcode); } +int32_t STORMAPI SErrGetErrorStr(uint32_t errorcode, char* buffer, uint32_t bufferchars) { + STORM_VALIDATE_BEGIN; + STORM_VALIDATE(buffer); + STORM_VALIDATE(bufferchars); + STORM_VALIDATE_END; + + buffer[0] = '\0'; +#if defined(WHOA_SYSTEM_WIN) + // half-measure + return FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, errorcode, LANG_USER_DEFAULT, buffer, bufferchars, nullptr); +#else + return 0; +#endif +} + +uint32_t STORMAPI SErrGetLastError() { + return s_lasterror; +} + int32_t STORMAPI SErrIsDisplayingError() { return s_displaying; } void STORMAPI SErrPrepareAppFatal(const char* filename, int32_t linenumber) { - // TODO + s_critsect.Enter(); + s_appFatInfo.filename = filename; + s_appFatInfo.linenumber = linenumber; + s_appFatInfo.threadId = StormGetThreadId(); + s_critsect.Leave(); } void STORMAPI SErrSetLastError(uint32_t errorcode) { @@ -96,10 +153,6 @@ void STORMAPI SErrSetLastError(uint32_t errorcode) { #endif } -uint32_t STORMAPI SErrGetLastError() { - return s_lasterror; -} - void STORMAPI SErrSuppressErrors(int32_t suppress) { s_suppress = suppress; } diff --git a/storm/Error.hpp b/storm/Error.hpp index 934402c9..c46667eb 100644 --- a/storm/Error.hpp +++ b/storm/Error.hpp @@ -29,14 +29,16 @@ int32_t STORMAPI SErrDisplayError(uint32_t errorcode, const char* filename, int3 int32_t STORMCDECL SErrDisplayErrorFmt(uint32_t errorcode, const char* filename, int32_t linenumber, int32_t recoverable, uint32_t exitcode, const char* format, ...); +int32_t STORMAPI SErrGetErrorStr(uint32_t errorcode, char* buffer, uint32_t bufferchars); + +uint32_t STORMAPI SErrGetLastError(); + int32_t STORMAPI SErrIsDisplayingError(); void STORMAPI SErrPrepareAppFatal(const char* filename, int32_t linenumber); void STORMAPI SErrSetLastError(uint32_t errorcode); -uint32_t STORMAPI SErrGetLastError(); - void STORMAPI SErrSuppressErrors(int32_t suppress); #endif diff --git a/test/Error.cpp b/test/Error.cpp index 8c7da411..45919b26 100644 --- a/test/Error.cpp +++ b/test/Error.cpp @@ -23,6 +23,15 @@ TEST_CASE("SErrDisplayErrorFmt", "[error]") { } } +TEST_CASE("SErrGetErrorStr", "[error]") { + SECTION("clears result buffer") { + // Use a fake error to almost guarantee it won't translate + char buffer[32] = "memes"; + CHECK(SErrGetErrorStr(0x12345678, buffer, sizeof(buffer)) == 0); + CHECK(std::string(buffer) == ""); + } +} + TEST_CASE("SErrIsDisplayingError", "[error]") { SECTION("returns false by default") { CHECK_FALSE(SErrIsDisplayingError()); diff --git a/test/stormdll/storm.def b/test/stormdll/storm.def index b17c23dc..8ba18f4e 100644 --- a/test/stormdll/storm.def +++ b/test/stormdll/storm.def @@ -277,7 +277,7 @@ EXPORTS ; Error ;SErrDestroy @460 NONAME SErrDisplayError @461 NONAME - ;SErrGetErrorStr @462 NONAME + SErrGetErrorStr @462 NONAME SErrGetLastError @463 NONAME ;SErrRegisterMessageSource @464 NONAME SErrSetLastError @465 NONAME diff --git a/test/stormdll/stormstubs.cpp b/test/stormdll/stormstubs.cpp index b0b68528..37776032 100644 --- a/test/stormdll/stormstubs.cpp +++ b/test/stormdll/stormstubs.cpp @@ -38,10 +38,11 @@ void STORMAPI SBigToUnsigned(BigData*, uint32_t*) {} void STORMCDECL SErrDisplayAppFatal(const char* format, ...) {} int32_t STORMAPI SErrDisplayError(uint32_t, const char*, int32_t, const char*, int32_t, uint32_t) { return 0; } int32_t STORMCDECL SErrDisplayErrorFmt(uint32_t, const char*, int32_t, int32_t, uint32_t, const char*, ...) { return 0; } +int32_t STORMAPI SErrGetErrorStr(uint32_t, char*, uint32_t) { return 0; } +uint32_t STORMAPI SErrGetLastError() { return 0; } int32_t STORMAPI SErrIsDisplayingError() { return 0; } void STORMAPI SErrPrepareAppFatal(const char*, int32_t) {} void STORMAPI SErrSetLastError(uint32_t) {} -uint32_t STORMAPI SErrGetLastError() { return 0; } void STORMAPI SErrSuppressErrors(int32_t) {} #include