diff --git a/source/lib/debug.cpp b/source/lib/debug.cpp index 7c9edd159d..af108dbe93 100644 --- a/source/lib/debug.cpp +++ b/source/lib/debug.cpp @@ -571,7 +571,8 @@ ErrorReaction debug_warn_err(int err, const char* file, int line, uint skip = 1; void* context = 0; wchar_t buf[400]; - swprintf(buf, ARRAY_SIZE(buf), L"Function call failed at %hs:%d (%hs): return value was %d", base_name, line, func, err); + char err_buf[200]; error_description_r(err, err_buf, ARRAY_SIZE(err_buf)); + swprintf(buf, ARRAY_SIZE(buf), L"Function call failed at %hs:%d (%hs): return value was %d (%hs)", base_name, line, func, err, err_buf); return display_error(buf, DE_ALLOW_SUPPRESS|DE_MANUAL_BREAK, skip, context, base_name, line); } diff --git a/source/lib/errors.cpp b/source/lib/errors.cpp new file mode 100644 index 0000000000..41640f295f --- /dev/null +++ b/source/lib/errors.cpp @@ -0,0 +1,75 @@ +#include "precompiled.h" + +#include "errors.h" +#include "sysdep/sysdep.h" + +#include +#include // abs + + +static const char* lib_error_description(int err) +{ + // not in our range + if(!(ERR_MIN <= abs(err) && abs(err) < ERR_MAX)) + return 0; + + switch(err) + { +#define ERR(err, id, str) case id: return str; +#include "errors.h" + default: return "Unknown lib error"; + } + UNREACHABLE; +} + + +void error_description_r(int err, char* buf, size_t max_chars) +{ + // lib error + const char* str = lib_error_description(err); + if(str) + { + // was one of our error codes (chosen so as not to conflict + // with any others), so we're done. + strcpy_s(buf, max_chars, str); + return; + } + + // Win32 GetLastError and errno both define values in [0,100). + // what we'll do is always try the OS-specific translation, + // add libc's interpretation if is a valid errno, and + // output "Unknown" if none of the above succeeds. + const bool should_display_libc_err = (0 <= err && err < sys_nerr); + bool have_output = false; + + // OS-specific error + if(sys_error_description_r(err, buf, max_chars) == 0) // success + { + have_output = true; + + // add a separator text before libc description + if(should_display_libc_err) + strcat_s(buf, max_chars, "; libc err="); + } + + // libc error + if(should_display_libc_err) + { + strcat_s(buf, max_chars, strerror(err)); + // note: we are sure to get meaningful output (not just "unknown") + // because err < sys_nerr. + have_output = true; + } + + // fallback + if(!have_output) + snprintf(buf, max_chars, "Unknown error (%d, 0x%X)", err, err); +} + + +const char* error_description(int err) +{ + static char buf[200]; + error_description_r(err, buf, ARRAY_SIZE(buf)); + return buf; +} \ No newline at end of file diff --git a/source/lib/errors.h b/source/lib/errors.h new file mode 100644 index 0000000000..1c25af69e7 --- /dev/null +++ b/source/lib/errors.h @@ -0,0 +1,70 @@ +// X macros: error code, symbolic name in code, user-visible string. +// error code is usually negative; positive denotes warnings. +// its absolute value must be within [ERR_MIN, ERR_MAX). +#ifdef ERR + +// function arguments +ERR(-100000, ERR_INVALID_PARAM, "Invalid function argument") +ERR(-100001, ERR_INVALID_HANDLE, "Invalid Handle (argument)") +ERR(-100002, ERR_BUF_SIZE, "Buffer argument too small") + +// system limitations +ERR(-100020, ERR_NO_MEM, "Not enough memory") +ERR(-100021, ERR_AGAIN, "Try again later") +ERR(-100022, ERR_LIMIT, "Fixed limit exceeded") +ERR(-100023, ERR_NO_SYS, "OS doesn't provide a required API") +ERR(-100024, ERR_NOT_IMPLEMENTED, "Feature currently not implemented") +ERR(-100025, ERR_NOT_SUPPORTED, "Feature isn't and won't be supported") + +ERR(-1060, ERR_TIMED_OUT, "Timed out") + +// file + vfs +ERR(-100200, ERR_FILE_NOT_FOUND, "VFile not found") +ERR(-100201, ERR_PATH_NOT_FOUND, "VDir not found") +ERR(-100202, ERR_PATH_LENGTH, "Path exceeds VFS_MAX_PATH characters") +ERR(-100203, ERR_PATH_INVALID, "Path is invalid") +ERR(-100210, ERR_DIR_END, "End of directory reached (no more files)") +ERR(-100220, ERR_NOT_FILE, "Not a file") +ERR(-100230, ERR_FILE_ACCESS, "Insufficient access rights to open file") +ERR(-100231, ERR_IO, "Error during IO") +ERR(-100232, ERR_EOF, "Reading beyond end of file") + +// file format +ERR(-100400, ERR_UNKNOWN_FORMAT, "Unknown file format") +ERR(-100401, ERR_INCOMPLETE_HEADER, "File header not completely read") +ERR(-100402, ERR_CORRUPTED, "File data is corrupted") + +// texture +ERR(-100500, ERR_TEX_FMT_INVALID, "Invalid/unsupported texture format") +ERR(-100501, ERR_TEX_INVALID_COLOR_TYPE, "Invalid color type") +ERR(-100502, ERR_TEX_NOT_8BIT_PRECISION, "Not 8-bit channel precision") +ERR(-100503, ERR_TEX_INVALID_LAYOUT, "Unsupported texel layout, e.g. right-to-left") +ERR(-100504, ERR_TEX_COMPRESSED, "Unsupported texture compression") +ERR(+100505, WARN_TEX_INVALID_DATA, "Warning: invalid texel data encountered") +ERR(-100506, ERR_TEX_INVALID_SIZE, "Texture size is incorrect") + +ERR(-100600, ERR_CPU_FEATURE_MISSING, "This CPU doesn't support a required feature") + +// shaders +ERR(-100700, ERR_SHDR_CREATE, "Shader creation failed") +ERR(-100701, ERR_SHDR_COMPILE, "Shader compile failed") +ERR(-100702, ERR_SHDR_NO_SHADER, "Invalid shader reference") +ERR(-100703, ERR_SHDR_LINK, "Shader linking failed") +ERR(-100704, ERR_SHDR_NO_PROGRAM, "Invalid shader program reference") + +#undef ERR +#endif // #ifdef ERR + + +//----------------------------------------------------------------------------- + +#ifndef ERRORS_H__ +#define ERRORS_H__ + +#define ERR_MIN 100000 +#define ERR_MAX 110000 + +extern const char* error_description(int err); +extern void error_description_r(int err, char* buf, size_t max_chars); + +#endif // #ifndef ERRORS_H__ \ No newline at end of file diff --git a/source/lib/lib.h b/source/lib/lib.h index 9c10caf2cf..c80bac57eb 100755 --- a/source/lib/lib.h +++ b/source/lib/lib.h @@ -59,6 +59,10 @@ scope #include "config.h" #include "lib/types.h" +// define error codes +#define ERR(err, id, str) const int id = err; +#include "lib/errors.h" + #include "sysdep/sysdep.h" #include "sysdep/cpu.h" // CAS @@ -231,70 +235,6 @@ STMT(\ ) -enum LibError -{ - // function arguments - ERR_INVALID_PARAM = -1000, - ERR_INVALID_HANDLE = -1001, - ERR_BUF_SIZE = -1002, - - // system limitations - // .. out of memory - ERR_NO_MEM = -1020, - // .. try again later - ERR_AGAIN = -1021, - // .. fixed limit exceeded - ERR_LIMIT = -1022, - // .. the OS doesn't provide an API we need - ERR_NO_SYS = -1023, - // .. feature not currently implemented (will probably change) - ERR_NOT_IMPLEMENTED = -1024, - // .. feature won't be supported - ERR_NOT_SUPPORTED = -1025, - - ERR_TIMED_OUT = -1060, - - // file + vfs - ERR_FILE_NOT_FOUND = -1200, - ERR_PATH_NOT_FOUND = -1201, - ERR_PATH_LENGTH = -1202, - ERR_PATH_INVALID = -1203, - ERR_DIR_END = -1210, - ERR_NOT_FILE = -1220, - ERR_FILE_ACCESS = -1230, - ERR_IO = -1231, - ERR_EOF = -1232, - - // file format - ERR_UNKNOWN_FORMAT = -1400, - ERR_INCOMPLETE_HEADER = -1401, - // .. data (e.g. in file) is obviously incorrect - ERR_CORRUPTED = -1402, - - // texture - ERR_TEX_FMT_INVALID = -1500, - ERR_TEX_INVALID_COLOR_TYPE = -1501, - ERR_TEX_NOT_8BIT_PRECISION = -1502, - ERR_TEX_INVALID_LAYOUT = -1503, - ERR_TEX_COMPRESSED = -1504, - WARN_TEX_INVALID_DATA = +1505, - ERR_TEX_INVALID_SIZE = -1506, - ERR_TEX_HEADER_NOT_COMPLETE = -1507, - - ERR_CPU_FEATURE_MISSING = -1600, - - // shaders - ERR_SHDR_CREATE = -1700, - ERR_SHDR_COMPILE = -1701, - ERR_SHDR_NO_SHADER = -1702, - ERR_SHDR_LINK = -1703, - ERR_SHDR_NO_PROGRAM = -1704, - - ERR_LAST -}; - - - #ifndef MIN #define MIN(a, b) (((a) < (b))? (a) : (b)) diff --git a/source/lib/res/file/vfs_path.cpp b/source/lib/res/file/vfs_path.cpp index d0a020e4d2..5f2a1f207d 100644 --- a/source/lib/res/file/vfs_path.cpp +++ b/source/lib/res/file/vfs_path.cpp @@ -31,7 +31,6 @@ int path_validate(const uint line, const char* path) size_t path_len = 0; // counted as we go; checked against max. const char* msg = 0; // error occurred <==> != 0 - int err = -1; // what we pass to caller int c = 0, last_c; // used for ./ detection @@ -78,12 +77,10 @@ int path_validate(const uint line, const char* path) goto ok; } - // failed somewhere - err is the error code, - // or -1 if not set specifically above. fail: - debug_printf("%s called from line %d failed: %s (error code %d)\n", __func__, line, msg, err); + debug_printf("%s called from line %d failed: %s\n", __func__, line, msg); debug_warn("failed"); - return err; + return -1; ok: return 0; diff --git a/source/lib/res/graphics/tex.cpp b/source/lib/res/graphics/tex.cpp index 0eea932fbb..d9f207d096 100755 --- a/source/lib/res/graphics/tex.cpp +++ b/source/lib/res/graphics/tex.cpp @@ -416,10 +416,10 @@ static int tex_load_impl(void* file_, size_t file_size, Tex* t) // make sure the entire header has been read const size_t min_hdr_size = c->hdr_size(0); if(file_size < min_hdr_size) - return ERR_TEX_HEADER_NOT_COMPLETE; + return ERR_INCOMPLETE_HEADER; const size_t hdr_size = c->hdr_size(file); if(file_size < hdr_size) - return ERR_TEX_HEADER_NOT_COMPLETE; + return ERR_INCOMPLETE_HEADER; t->ofs = hdr_size; DynArray da; diff --git a/source/lib/res/graphics/tex_codec.cpp b/source/lib/res/graphics/tex_codec.cpp index 32fa005a1e..f42f3985a5 100644 --- a/source/lib/res/graphics/tex_codec.cpp +++ b/source/lib/res/graphics/tex_codec.cpp @@ -48,7 +48,7 @@ int tex_codec_for_header(const u8* file, size_t file_size, const TexCodecVTbl** { // we guarantee at least 4 bytes for is_hdr to look at if(file_size < 4) - return ERR_TEX_HEADER_NOT_COMPLETE; + return ERR_INCOMPLETE_HEADER; for(*c = codecs; *c; *c = (*c)->next) { diff --git a/source/lib/sysdep/sysdep.h b/source/lib/sysdep/sysdep.h index 8ed176d000..1c1bcd508e 100755 --- a/source/lib/sysdep/sysdep.h +++ b/source/lib/sysdep/sysdep.h @@ -212,6 +212,8 @@ extern int sys_cursor_free(void* cursor); +extern int sys_error_description_r(int err, char* buf, size_t max_chars); + extern int get_executable_name(char* n_path, size_t buf_size); // return filename of the module which contains address , diff --git a/source/lib/sysdep/win/win.cpp b/source/lib/sysdep/win/win.cpp index 5d31ffcb50..0099e5f290 100755 --- a/source/lib/sysdep/win/win.cpp +++ b/source/lib/sysdep/win/win.cpp @@ -37,7 +37,6 @@ char win_sys_dir[MAX_PATH+1]; char win_exe_dir[MAX_PATH+1]; - // we need to know the app's main window for the error dialog, so that // it is modal and actually stops the app. if it keeps running while // we're reporting an error, it'll probably crash and take down the @@ -634,6 +633,27 @@ int sys_cursor_free(void* cursor) } +//----------------------------------------------------------------------------- + + +int sys_error_description_r(int err, char* buf, size_t max_chars) +{ + // not in our range (Win32 error numbers are positive) + if(err < 0) + return -1; + + const LPCVOID source = 0; // ignored (we're not using FROM_HMODULE etc.) + const DWORD lang_id = 0; // look for neutral, then current locale + va_list* args = 0; // we don't care about "inserts" + DWORD ret = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, source, (DWORD)err, + lang_id, buf, (DWORD)max_chars, args); + if(!ret) + return -1; + debug_assert(ret < max_chars); // ret = #chars output + return 0; +} + + /////////////////////////////////////////////////////////////////////////////// // // module init and shutdown mechanism