diff --git a/src/Bitmap.c b/src/Bitmap.c index 07f9a3560..c258b5676 100644 --- a/src/Bitmap.c +++ b/src/Bitmap.c @@ -367,7 +367,7 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) { switch (fourCC) { case PNG_FourCC('I','H','D','R'): { - if (dataSize != PNG_IHDR_SIZE) return PNG_ERR_INVALID_HEADER_SIZE; + if (dataSize != PNG_IHDR_SIZE) return PNG_ERR_INVALID_HDR_SIZE; res = Stream_Read(stream, tmp, PNG_IHDR_SIZE); if (res) return res; diff --git a/src/Errors.h b/src/Errors.h index c35ce6831..2f475c183 100644 --- a/src/Errors.h +++ b/src/Errors.h @@ -4,6 +4,7 @@ Copyright 2017 ClassicalSharp | Licensed under BSD-3 */ +/* NOTE: When changing these, remember to keep Logger.C up to date! */ enum ERRORS_ALL { ERROR_BASE = 0xCCDED000UL, ERR_END_OF_STREAM, @@ -23,7 +24,7 @@ enum ERRORS_ALL { VORBIS_ERR_MAPPING_CHANS, VORBIS_ERR_MAPPING_RESERVED, VORBIS_ERR_FRAME_TYPE, /* PNG image decoding errors */ - PNG_ERR_INVALID_SIG, PNG_ERR_INVALID_HEADER_SIZE, PNG_ERR_TOO_WIDE, PNG_ERR_TOO_TALL, + PNG_ERR_INVALID_SIG, PNG_ERR_INVALID_HDR_SIZE, PNG_ERR_TOO_WIDE, PNG_ERR_TOO_TALL, PNG_ERR_INVALID_COL_BPP, PNG_ERR_COMP_METHOD, PNG_ERR_FILTER, PNG_ERR_INTERLACED, PNG_ERR_PAL_ENTRIES, PNG_ERR_PAL_SIZE, PNG_ERR_TRANS_COUNT, PNG_ERR_TRANS_INVALID, PNG_ERR_INVALID_END_SIZE, PNG_ERR_NO_DATA, diff --git a/src/Game.c b/src/Game.c index 5dde6038b..07c1b23b0 100644 --- a/src/Game.c +++ b/src/Game.c @@ -314,7 +314,14 @@ static void Game_OnLowVRAMDetected(void* obj) { Chat_AddRaw("&cOut of VRAM! Halving view distance.."); } -static void Game_WarnFunc(const String* msg) { Chat_Add1("&c%s", msg); } +static void Game_WarnFunc(const String* msg) { + String str = *msg, line; + while (str.length) { + String_UNSAFE_SplitBy(&str, '\n', &line); + Chat_Add1("&c%s", &line); + } +} + static void Game_ExtractInitialTexturePack(void) { String texPack; char texPackBuffer[STRING_SIZE]; @@ -405,7 +412,7 @@ static void Game_LoadPlugins(void) { ReturnCode res; res = Directory_Enum(&dir, NULL, Game_LoadPlugin); - if (res) Logger_OldWarn(res, "enumerating plugins directory"); + if (res) Logger_Warn(res, "enumerating plugins directory"); } void Game_Free(void* obj); diff --git a/src/LScreens.c b/src/LScreens.c index afa325dbd..10cb8c89d 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -1567,10 +1567,10 @@ static void UpdatesScreen_Init(struct LScreen* s_) { String_InitArray(path, pathBuffer); res = Process_GetExePath(&path); - if (res) { Logger_OldWarn(res, "getting .exe path"); return; } + if (res) { Logger_Warn(res, "getting .exe path"); return; } res = File_GetModifiedTime(&path, &buildTime); - if (res) { Logger_OldWarn(res, "getting build time"); return; } + if (res) { Logger_Warn(res, "getting build time"); return; } UpdatesScreen_Format(&s->LblYour, "Your build: ", buildTime); } diff --git a/src/LWeb.c b/src/LWeb.c index 2ec25e652..33f25245a 100644 --- a/src/LWeb.c +++ b/src/LWeb.c @@ -494,13 +494,13 @@ static void FetchUpdateTask_Handle(uint8_t* data, uint32_t len) { ReturnCode res; res = Stream_WriteAllTo(&path, data, len); - if (res) { Logger_OldWarn(res, "saving update"); return; } + if (res) { Logger_Warn(res, "saving update"); return; } res = File_SetModifiedTime(&path, FetchUpdateTask.Timestamp); - if (res) Logger_OldWarn(res, "setting update time"); + if (res) Logger_Warn(res, "setting update time"); res = Platform_MarkExecutable(&path); - if (res) Logger_OldWarn(res, "making update executable"); + if (res) Logger_Warn(res, "making update executable"); } void FetchUpdateTask_Run(bool release, bool d3d9) { @@ -565,7 +565,7 @@ static void FetchFlagsTask_Handle(uint8_t* data, uint32_t len) { Stream_ReadonlyMemory(&s, data, len); res = Png_Decode(&flags[FetchFlagsTask.Count].Bmp, &s); - if (res) Logger_OldWarn(res, "decoding flag"); + if (res) Logger_Warn(res, "decoding flag"); FetchFlagsTask.Count++; FetchFlagsTask_DownloadNext(); diff --git a/src/Launcher.c b/src/Launcher.c index 657f8eed6..fc3c291bf 100644 --- a/src/Launcher.c +++ b/src/Launcher.c @@ -364,7 +364,7 @@ static ReturnCode Launcher_ProcessZipEntry(const String* path, struct Stream* da res = Png_Decode(&fontBmp, data); if (res) { - Logger_OldWarn(res, "decoding default.png"); return res; + Logger_Warn(res, "decoding default.png"); return res; } else { Drawer2D_SetFontBitmap(&fontBmp); useBitmappedFont = !Options_GetBool(OPT_USE_CHAT_FONT, false); @@ -374,7 +374,7 @@ static ReturnCode Launcher_ProcessZipEntry(const String* path, struct Stream* da res = Png_Decode(&bmp, data); if (res) { - Logger_OldWarn(res, "decoding terrain.png"); return res; + Logger_Warn(res, "decoding terrain.png"); return res; } else { Launcher_LoadTextures(&bmp); } @@ -388,18 +388,14 @@ static void Launcher_ExtractTexturePack(const String* path) { ReturnCode res; res = Stream_OpenFile(&stream, path); - if (res) { - Logger_OldWarn(res, "opening texture pack"); return; - } + if (res) { Logger_Warn(res, "opening texture pack"); return; } Zip_Init(&state, &stream); state.SelectEntry = Launcher_SelectZipEntry; state.ProcessEntry = Launcher_ProcessZipEntry; res = Zip_Extract(&state); - if (res) { - Logger_OldWarn(res, "extracting texture pack"); - } + if (res) { Logger_Warn(res, "extracting texture pack"); } stream.Close(&stream); } @@ -534,7 +530,7 @@ bool Launcher_StartGame(const String* user, const String* mppass, const String* String_InitArray(path, pathBuffer); res = Process_GetExePath(&path); - if (res) { Logger_OldWarn(res, "getting .exe path"); return false; } + if (res) { Logger_Warn(res, "getting .exe path"); return false; } String_InitArray(args, argsBuffer); String_AppendString(&args, user); @@ -546,7 +542,7 @@ bool Launcher_StartGame(const String* user, const String* mppass, const String* /* HRESULT when user clicks 'cancel' to 'are you sure you want to run ClassiCube.exe' */ if (res == 0x80004005) return; #endif - if (res) { Logger_OldWarn(res, "starting game"); return false; } + if (res) { Logger_Warn(res, "starting game"); return false; } Launcher_ShouldExit = Options_GetBool(OPT_AUTO_CLOSE_LAUNCHER, false); return true; @@ -614,7 +610,7 @@ static void Launcher_ApplyUpdate(void) { String_InitArray(exe, exeBuffer); res = Process_GetExePath(&exe); - if (res) { Logger_OldWarn(res, "getting executable path"); return; } + if (res) { Logger_Warn(res, "getting executable path"); return; } Utils_UNSAFE_GetFilename(&exe); String_InitArray(str, strBuffer); @@ -622,12 +618,12 @@ static void Launcher_ApplyUpdate(void) { /* Can't use WriteLine, want \n as actual newline not code page 437 */ res = Stream_WriteAllTo(&scriptPath, (const uint8_t*)str.buffer, str.length); - if (res) { Logger_OldWarn(res, "saving update script"); return; } + if (res) { Logger_Warn(res, "saving update script"); return; } res = Platform_MarkExecutable(&scriptPath); - if (res) Logger_OldWarn(res, "making update script executable"); + if (res) Logger_Warn(res, "making update script executable"); res = Process_Start(&scriptName, &scriptArgs); - if (res) { Logger_OldWarn(res, "starting update script"); return; } + if (res) { Logger_Warn(res, "starting update script"); return; } } #endif diff --git a/src/Logger.c b/src/Logger.c index 7a8b9b447..5dea55466 100644 --- a/src/Logger.c +++ b/src/Logger.c @@ -4,23 +4,11 @@ #include "Window.h" #include "Funcs.h" #include "Stream.h" - -static void Logger_AbortCommon(ReturnCode result, const char* raw_msg, void* ctx); +#include "Errors.h" #ifdef CC_BUILD_WEB -/* Can't see native CPU state with javascript */ -#undef CC_BUILD_POSIX - -static void Logger_DumpBacktrace(String* str, void* ctx) { } -static void Logger_DumpRegisters(void* ctx) { } -static void Logger_DumpMisc(void* ctx) { } - -void Logger_Hook(void) { } -void Logger_Abort2(ReturnCode result, const char* raw_msg) { - Logger_AbortCommon(result, raw_msg, NULL); -} +#undef CC_BUILD_POSIX /* Can't see native CPU state with javascript */ #endif - #ifdef CC_BUILD_WIN #define WIN32_LEAN_AND_MEAN #define NOSERVICE @@ -28,49 +16,198 @@ void Logger_Abort2(ReturnCode result, const char* raw_msg) { #define NOIME #include #include +#endif +/* POSIX can be shared between Linux/BSD/OSX */ +#ifdef CC_BUILD_POSIX +#ifndef CC_BUILD_OPENBSD +#include +#endif +#include +#include +#include +#include +#include +#endif -struct StackPointers { uintptr_t Instruction, Frame, Stack; }; -struct SymbolAndName { IMAGEHLP_SYMBOL Symbol; char Name[256]; }; + +/*########################################################################################################################* +*----------------------------------------------------------Warning--------------------------------------------------------* +*#########################################################################################################################*/ +void Logger_DialogWarn(const String* msg) { + String dst; char dstBuffer[512]; + String_InitArray_NT(dst, dstBuffer); + + String_AppendString(&dst, msg); + dst.buffer[dst.length] = '\0'; + Window_ShowDialog(Logger_DialogTitle, dst.buffer); +} +const char* Logger_DialogTitle = "Error"; +Logger_DoWarn Logger_WarnFunc = Logger_DialogWarn; + +void Logger_OldWarn(ReturnCode res, const char* place) { + String msg; char msgBuffer[128]; + String_InitArray(msg, msgBuffer); + + String_Format2(&msg, "Error %h when %c", &res, place); + Logger_WarnFunc(&msg); +} + +void Logger_OldWarn2(ReturnCode res, const char* place, const String* path) { + String msg; char msgBuffer[256]; + String_InitArray(msg, msgBuffer); + + String_Format3(&msg, "Error %h when %c '%s'", &res, place, path); + Logger_WarnFunc(&msg); +} + +/* Returns a description for ClassiCube specific error codes */ +static const char* Logger_GetCCErrorDesc(ReturnCode res) { + switch (res) { + case ERR_END_OF_STREAM: return "End of stream"; + case OGG_ERR_INVALID_SIG: return "Invalid OGG signature"; + case OGG_ERR_VERSION: return "Invalid OGG format version"; + + /*WAV_ERR_STREAM_HDR, + WAV_ERR_STREAM_TYPE, + WAV_ERR_DATA_TYPE, + WAV_ERR_NO_DATA, + /* Vorbis audio decoding errors */ /* + VORBIS_ERR_HEADER, + VORBIS_ERR_WRONG_HEADER, + VORBIS_ERR_FRAMING, + VORBIS_ERR_VERSION, + VORBIS_ERR_BLOCKSIZE, + VORBIS_ERR_CHANS, + VORBIS_ERR_TIME_TYPE, + VORBIS_ERR_FLOOR_TYPE, + VORBIS_ERR_RESIDUE_TYPE, + VORBIS_ERR_MAPPING_TYPE, + VORBIS_ERR_MODE_TYPE, + VORBIS_ERR_CODEBOOK_SYNC, + VORBIS_ERR_CODEBOOK_ENTRY, + VORBIS_ERR_CODEBOOK_LOOKUP, + VORBIS_ERR_MODE_WINDOW, + VORBIS_ERR_MODE_TRANSFORM, + VORBIS_ERR_MAPPING_CHANS, + VORBIS_ERR_MAPPING_RESERVED, + VORBIS_ERR_FRAME_TYPE, + /* PNG image decoding errors */ /* + PNG_ERR_INVALID_SIG, + PNG_ERR_INVALID_HDR_SIZE, + PNG_ERR_TOO_WIDE, + PNG_ERR_TOO_TALL, + PNG_ERR_INVALID_COL_BPP, + PNG_ERR_COMP_METHOD, + PNG_ERR_FILTER, + PNG_ERR_INTERLACED, + PNG_ERR_PAL_ENTRIES, + PNG_ERR_PAL_SIZE, + PNG_ERR_TRANS_COUNT, + PNG_ERR_TRANS_INVALID, + PNG_ERR_INVALID_END_SIZE, + PNG_ERR_NO_DATA, + /* ZIP archive decoding errors */ /* + ZIP_ERR_TOO_MANY_ENTRIES, + ZIP_ERR_SEEK_END_OF_CENTRAL_DIR, + ZIP_ERR_NO_END_OF_CENTRAL_DIR, + ZIP_ERR_SEEK_CENTRAL_DIR, + ZIP_ERR_INVALID_CENTRAL_DIR, + ZIP_ERR_SEEK_LOCAL_DIR, + ZIP_ERR_INVALID_LOCAL_DIR, + ZIP_ERR_FILENAME_LEN, + /* GZIP header decoding errors */ /* + GZIP_ERR_HEADER1, + GZIP_ERR_HEADER2, + GZIP_ERR_METHOD, + GZIP_ERR_FLAGS, + /* ZLIB header decoding errors */ /* + ZLIB_ERR_METHOD, + ZLIB_ERR_WINDOW_SIZE, + ZLIB_ERR_FLAGS, + /* FCM map decoding errors */ /* + FCM_ERR_IDENTIFIER, + FCM_ERR_REVISION, + /* LVL map decoding errors */ /* + LVL_ERR_VERSION, + /* DAT map decoding errors */ /* + DAT_ERR_IDENTIFIER, + DAT_ERR_VERSION, + DAT_ERR_JIDENTIFIER, + DAT_ERR_JVERSION, + DAT_ERR_ROOT_TYPE, + DAT_ERR_JSTRING_LEN, + DAT_ERR_JFIELD_CLASS_NAME, + DAT_ERR_JCLASS_TYPE, + DAT_ERR_JCLASS_FIELDS, + DAT_ERR_JCLASS_ANNOTATION, + DAT_ERR_JOBJECT_TYPE, + DAT_ERR_JARRAY_TYPE, + DAT_ERR_JARRAY_CONTENT, + /* CW map decoding errors */ /* + NBT_ERR_INT32S, + NBT_ERR_UNKNOWN, + CW_ERR_ROOT_TAG, + CW_ERR_STRING_LEN + */ + + case PNG_ERR_INVALID_SIG: return "Invalid PNG signature"; + case PNG_ERR_INVALID_HDR_SIZE: return "Invalid PNG header size"; + case PNG_ERR_TOO_WIDE: return "PNG image too wide"; + case PNG_ERR_TOO_TALL: return "PNG image too tall"; + case PNG_ERR_INTERLACED: return "Interlaced PNGs unsupported"; + } + return NULL; +} + +/* Appends more detailed information about an error if possible */ +static void Logger_AppendErrorDesc(String* msg, ReturnCode res, Logger_DescribeError describeErr) { + const char* cc_err; + String err; char errBuffer[128]; + String_InitArray(err, errBuffer); + + cc_err = Logger_GetCCErrorDesc(res); + if (cc_err) { + String_Format1(msg, "\n Error meaning: %c", cc_err); + } else if (describeErr(res, &err)) { + String_Format1(msg, "\n Error meaning: %s", &err); + } +} + +void Logger_SysWarn(ReturnCode res, const char* place, Logger_DescribeError describeErr) { + String msg; char msgBuffer[256]; + String_InitArray(msg, msgBuffer); + + String_Format2(&msg, "Error %h when %c", &res, place); + Logger_AppendErrorDesc(&msg, res, describeErr); + Logger_WarnFunc(&msg); +} + +void Logger_SysWarn2(ReturnCode res, const char* place, const String* path, Logger_DescribeError describeErr) { + String msg; char msgBuffer[256]; + String_InitArray(msg, msgBuffer); + + String_Format3(&msg, "Error %h when %c '%s'", &res, place, path); + Logger_AppendErrorDesc(&msg, res, describeErr); + Logger_WarnFunc(&msg); +} + +void Logger_DynamicLibWarn2(ReturnCode res, const char* place, const String* path) { + Logger_SysWarn2(res, place, path, DynamicLib_DescribeError); +} +void Logger_Warn(ReturnCode res, const char* place) { + Logger_SysWarn(res, place, Platform_DescribeError); +} +void Logger_Warn2(ReturnCode res, const char* place, const String* path) { + Logger_SysWarn2(res, place, path, Platform_DescribeError); +} /*########################################################################################################################* *-------------------------------------------------------Info dumping------------------------------------------------------* *#########################################################################################################################*/ -static void Logger_DumpRegisters(void* ctx) { - String str; char strBuffer[512]; - CONTEXT* r = (CONTEXT*)ctx; - - String_InitArray(str, strBuffer); - String_AppendConst(&str, "-- registers --\r\n"); - -#if defined _M_IX86 - String_Format3(&str, "eax=%x ebx=%x ecx=%x\r\n", &r->Eax, &r->Ebx, &r->Ecx); - String_Format3(&str, "edx=%x esi=%x edi=%x\r\n", &r->Edx, &r->Esi, &r->Edi); - String_Format3(&str, "eip=%x ebp=%x esp=%x\r\n", &r->Eip, &r->Ebp, &r->Esp); -#elif defined _M_X64 - String_Format3(&str, "rax=%x rbx=%x rcx=%x\r\n", &r->Rax, &r->Rbx, &r->Rcx); - String_Format3(&str, "rdx=%x rsi=%x rdi=%x\r\n", &r->Rdx, &r->Rsi, &r->Rdi); - String_Format3(&str, "rip=%x rbp=%x rsp=%x\r\n", &r->Rip, &r->Rbp, &r->Rsp); - String_Format3(&str, "r8 =%x r9 =%x r10=%x\r\n", &r->R8, &r->R9, &r->R10); - String_Format3(&str, "r11=%x r12=%x r13=%x\r\n", &r->R11, &r->R12, &r->R13); - String_Format2(&str, "r14=%x r15=%x\r\n" , &r->R14, &r->R15); -#elif defined _M_IA64 - String_Format3(&str, "r1 =%x r2 =%x r3 =%x\r\n", &r->IntGp, &r->IntT0, &r->IntT1); - String_Format3(&str, "r4 =%x r5 =%x r6 =%x\r\n", &r->IntS0, &r->IntS1, &r->IntS2); - String_Format3(&str, "r7 =%x r8 =%x r9 =%x\r\n", &r->IntS3, &r->IntV0, &r->IntT2); - String_Format3(&str, "r10=%x r11=%x r12=%x\r\n", &r->IntT3, &r->IntT4, &r->IntSp); - String_Format3(&str, "r13=%x r14=%x r15=%x\r\n", &r->IntTeb, &r->IntT5, &r->IntT6); - String_Format3(&str, "r16=%x r17=%x r18=%x\r\n", &r->IntT7, &r->IntT8, &r->IntT9); - String_Format3(&str, "r19=%x r20=%x r21=%x\r\n", &r->IntT10, &r->IntT11, &r->IntT12); - String_Format3(&str, "r22=%x r23=%x r24=%x\r\n", &r->IntT13, &r->IntT14, &r->IntT15); - String_Format3(&str, "r25=%x r26=%x r27=%x\r\n", &r->IntT16, &r->IntT17, &r->IntT18); - String_Format3(&str, "r28=%x r29=%x r30=%x\r\n", &r->IntT19, &r->IntT20, &r->IntT21); - String_Format3(&str, "r31=%x nat=%x pre=%x\r\n", &r->IntT22, &r->IntNats,&r->Preds); -#else -#error "Unknown machine type" -#endif - Logger_Log(&str); -} +#if defined CC_BUILD_WIN +struct StackPointers { uintptr_t Instruction, Frame, Stack; }; +struct SymbolAndName { IMAGEHLP_SYMBOL Symbol; char Name[256]; }; static int Logger_GetFrames(CONTEXT* ctx, struct StackPointers* pointers, int max) { STACKFRAME frame = { 0 }; @@ -170,6 +307,42 @@ static void Logger_DumpBacktrace(String* str, void* ctx) { Logger_Backtrace(str, ctx); } +static void Logger_DumpRegisters(void* ctx) { + String str; char strBuffer[512]; + CONTEXT* r = (CONTEXT*)ctx; + + String_InitArray(str, strBuffer); + String_AppendConst(&str, "-- registers --\r\n"); + +#if defined _M_IX86 + String_Format3(&str, "eax=%x ebx=%x ecx=%x\r\n", &r->Eax, &r->Ebx, &r->Ecx); + String_Format3(&str, "edx=%x esi=%x edi=%x\r\n", &r->Edx, &r->Esi, &r->Edi); + String_Format3(&str, "eip=%x ebp=%x esp=%x\r\n", &r->Eip, &r->Ebp, &r->Esp); +#elif defined _M_X64 + String_Format3(&str, "rax=%x rbx=%x rcx=%x\r\n", &r->Rax, &r->Rbx, &r->Rcx); + String_Format3(&str, "rdx=%x rsi=%x rdi=%x\r\n", &r->Rdx, &r->Rsi, &r->Rdi); + String_Format3(&str, "rip=%x rbp=%x rsp=%x\r\n", &r->Rip, &r->Rbp, &r->Rsp); + String_Format3(&str, "r8 =%x r9 =%x r10=%x\r\n", &r->R8, &r->R9, &r->R10); + String_Format3(&str, "r11=%x r12=%x r13=%x\r\n", &r->R11, &r->R12, &r->R13); + String_Format2(&str, "r14=%x r15=%x\r\n" , &r->R14, &r->R15); +#elif defined _M_IA64 + String_Format3(&str, "r1 =%x r2 =%x r3 =%x\r\n", &r->IntGp, &r->IntT0, &r->IntT1); + String_Format3(&str, "r4 =%x r5 =%x r6 =%x\r\n", &r->IntS0, &r->IntS1, &r->IntS2); + String_Format3(&str, "r7 =%x r8 =%x r9 =%x\r\n", &r->IntS3, &r->IntV0, &r->IntT2); + String_Format3(&str, "r10=%x r11=%x r12=%x\r\n", &r->IntT3, &r->IntT4, &r->IntSp); + String_Format3(&str, "r13=%x r14=%x r15=%x\r\n", &r->IntTeb, &r->IntT5, &r->IntT6); + String_Format3(&str, "r16=%x r17=%x r18=%x\r\n", &r->IntT7, &r->IntT8, &r->IntT9); + String_Format3(&str, "r19=%x r20=%x r21=%x\r\n", &r->IntT10, &r->IntT11, &r->IntT12); + String_Format3(&str, "r22=%x r23=%x r24=%x\r\n", &r->IntT13, &r->IntT14, &r->IntT15); + String_Format3(&str, "r25=%x r26=%x r27=%x\r\n", &r->IntT16, &r->IntT17, &r->IntT18); + String_Format3(&str, "r28=%x r29=%x r30=%x\r\n", &r->IntT19, &r->IntT20, &r->IntT21); + String_Format3(&str, "r31=%x nat=%x pre=%x\r\n", &r->IntT22, &r->IntNats,&r->Preds); +#else +#error "Unknown machine type" +#endif + Logger_Log(&str); +} + static BOOL CALLBACK Logger_DumpModule(const char* name, ULONG_PTR base, ULONG size, void* ctx) { String str; char strBuffer[256]; uintptr_t beg, end; @@ -190,94 +363,8 @@ static void Logger_DumpMisc(void* ctx) { EnumerateLoadedModules(process, Logger_DumpModule, NULL); } - -/*########################################################################################################################* -*------------------------------------------------------Error handling-----------------------------------------------------* -*#########################################################################################################################*/ -static LONG WINAPI Logger_UnhandledFilter(struct _EXCEPTION_POINTERS* pInfo) { - String msg; char msgBuffer[STRING_SIZE * 2 + 1]; - uint32_t code; - uintptr_t addr; - - code = (uint32_t)pInfo->ExceptionRecord->ExceptionCode; - addr = (uintptr_t)pInfo->ExceptionRecord->ExceptionAddress; - - String_InitArray_NT(msg, msgBuffer); - String_Format2(&msg, "Unhandled exception 0x%h at 0x%x", &code, &addr); - msg.buffer[msg.length] = '\0'; - - Logger_AbortCommon(0, msg.buffer, pInfo->ContextRecord); - return EXCEPTION_EXECUTE_HANDLER; /* TODO: different flag */ -} - -void Logger_Hook(void) { - SetUnhandledExceptionFilter(Logger_UnhandledFilter); -} - -/* Don't want compiler doing anything fancy with registers */ -#if _MSC_VER -#pragma optimize ("", off) #endif -void Logger_Abort2(ReturnCode result, const char* raw_msg) { - CONTEXT ctx; -#ifndef _M_IX86 - /* This method is guaranteed to exist on 64 bit windows */ - /* It is missing in 32 bit Windows 2000 however */ - RtlCaptureContext(&ctx); -#elif _MSC_VER - /* Stack frame layout on x86: */ - /* [ebp] is previous frame's EBP */ - /* [ebp+4] is previous frame's EIP (return address) */ - /* address of [ebp+8] is previous frame's ESP */ - __asm { - mov eax, [ebp] - mov [ctx.Ebp], eax - mov eax, [ebp+4] - mov [ctx.Eip], eax - lea eax, [ebp+8] - mov [ctx.Esp], eax - mov [ctx.ContextFlags], CONTEXT_CONTROL - } -#else - int32_t _ebp, _eip, _esp; - /* TODO: I think this is right, not sure.. */ - __asm__( - "mov 0(%%ebp), %%eax \n\t" - "mov %%eax, %0 \n\t" - "mov 4(%%ebp), %%eax \n\t" - "mov %%eax, %1 \n\t" - "lea 8(%%ebp), %%eax \n\t" - "mov %%eax, %2" - : "=m" (_ebp), "=m" (_eip), "=m" (_esp) - : - : "eax", "memory"); - - ctx.Ebp = _ebp; - ctx.Eip = _eip; - ctx.Esp = _esp; - ctx.ContextFlags = CONTEXT_CONTROL; -#endif - - Logger_AbortCommon(result, raw_msg, &ctx); -} -#if _MSC_VER -#pragma optimize ("", on) -#endif -#endif -/* POSIX can be shared between Linux/BSD/OSX */ #ifdef CC_BUILD_POSIX -#ifndef CC_BUILD_OPENBSD -#include -#endif -#include -#include -#include -#include -#include - -/*########################################################################################################################* -*-------------------------------------------------------Info dumping------------------------------------------------------* -*#########################################################################################################################*/ static void Logger_Backtrace(String* backtrace_, void* ctx) { String str; char strBuffer[384]; void* addrs[40]; @@ -314,58 +401,6 @@ static void Logger_DumpBacktrace(String* str, void* ctx) { Logger_Backtrace(str, ctx); } - -/*########################################################################################################################* -*------------------------------------------------------Error handling-----------------------------------------------------* -*#########################################################################################################################*/ -static void Logger_SignalHandler(int sig, siginfo_t* info, void* ctx) { - String msg; char msgBuffer[STRING_SIZE * 2 + 1]; - int type, code; - uintptr_t addr; - - /* Uninstall handler to avoid chance of infinite loop */ - signal(SIGSEGV, SIG_DFL); - signal(SIGBUS, SIG_DFL); - signal(SIGILL, SIG_DFL); - signal(SIGABRT, SIG_DFL); - signal(SIGFPE, SIG_DFL); - - type = info->si_signo; - code = info->si_code; - addr = (uintptr_t)info->si_addr; - - String_InitArray_NT(msg, msgBuffer); - String_Format3(&msg, "Unhandled signal %i (code %i) at 0x%x", &type, &code, &addr); - msg.buffer[msg.length] = '\0'; - - Logger_AbortCommon(0, msg.buffer, ctx); -} - -void Logger_Hook(void) { - struct sigaction sa, old; - sa.sa_sigaction = Logger_SignalHandler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART | SA_SIGINFO; - - sigaction(SIGSEGV, &sa, &old); - sigaction(SIGBUS, &sa, &old); - sigaction(SIGILL, &sa, &old); - sigaction(SIGABRT, &sa, &old); - sigaction(SIGFPE, &sa, &old); -} - -void Logger_Abort2(ReturnCode result, const char* raw_msg) { - ucontext_t ctx; - getcontext(&ctx); - Logger_AbortCommon(result, raw_msg, &ctx); -} -#endif - - -/*########################################################################################################################* -*-------------------------------------------------------Info dumping------------------------------------------------------* -*#########################################################################################################################*/ -#ifdef CC_BUILD_POSIX static void Logger_DumpRegisters(void* ctx) { String str; char strBuffer[512]; #ifdef CC_BUILD_OPENBSD @@ -451,8 +486,8 @@ static void Logger_DumpRegisters(void* ctx) { Logger_Log(&str); } -#endif +/* OS specific stuff */ #if defined CC_BUILD_LINUX || defined CC_BUILD_SOLARIS static void Logger_DumpMisc(void* ctx) { const static String memMap = String_FromConst("-- memory map --\n"); @@ -472,76 +507,143 @@ static void Logger_DumpMisc(void* ctx) { close(fd); } -#elif defined CC_BUILD_OSX || defined CC_BUILD_FREEBSD || defined CC_BUILD_OPENBSD +#else static void Logger_DumpMisc(void* ctx) { } #endif +#endif +#ifdef CC_BUILD_WEB +static void Logger_DumpBacktrace(String* str, void* ctx) { } +static void Logger_DumpRegisters(void* ctx) { } +static void Logger_DumpMisc(void* ctx) { } +#endif + +/*########################################################################################################################* +*------------------------------------------------------Error handling-----------------------------------------------------* +*#########################################################################################################################*/ +static void Logger_AbortCommon(ReturnCode result, const char* raw_msg, void* ctx); + +#ifdef CC_BUILD_WIN +static LONG WINAPI Logger_UnhandledFilter(struct _EXCEPTION_POINTERS* pInfo) { + String msg; char msgBuffer[STRING_SIZE * 2 + 1]; + uint32_t code; + uintptr_t addr; + + code = (uint32_t)pInfo->ExceptionRecord->ExceptionCode; + addr = (uintptr_t)pInfo->ExceptionRecord->ExceptionAddress; + + String_InitArray_NT(msg, msgBuffer); + String_Format2(&msg, "Unhandled exception 0x%h at 0x%x", &code, &addr); + msg.buffer[msg.length] = '\0'; + + Logger_AbortCommon(0, msg.buffer, pInfo->ContextRecord); + return EXCEPTION_EXECUTE_HANDLER; /* TODO: different flag */ +} +void Logger_Hook(void) { SetUnhandledExceptionFilter(Logger_UnhandledFilter); } + +/* Don't want compiler doing anything fancy with registers */ +#if _MSC_VER +#pragma optimize ("", off) +#endif +void Logger_Abort2(ReturnCode result, const char* raw_msg) { + CONTEXT ctx; +#ifndef _M_IX86 + /* This method is guaranteed to exist on 64 bit windows */ + /* It is missing in 32 bit Windows 2000 however */ + RtlCaptureContext(&ctx); +#elif _MSC_VER + /* Stack frame layout on x86: */ + /* [ebp] is previous frame's EBP */ + /* [ebp+4] is previous frame's EIP (return address) */ + /* address of [ebp+8] is previous frame's ESP */ + __asm { + mov eax, [ebp] + mov [ctx.Ebp], eax + mov eax, [ebp+4] + mov [ctx.Eip], eax + lea eax, [ebp+8] + mov [ctx.Esp], eax + mov [ctx.ContextFlags], CONTEXT_CONTROL + } +#else + int32_t _ebp, _eip, _esp; + /* TODO: I think this is right, not sure.. */ + __asm__( + "mov 0(%%ebp), %%eax \n\t" + "mov %%eax, %0 \n\t" + "mov 4(%%ebp), %%eax \n\t" + "mov %%eax, %1 \n\t" + "lea 8(%%ebp), %%eax \n\t" + "mov %%eax, %2" + : "=m" (_ebp), "=m" (_eip), "=m" (_esp) + : + : "eax", "memory"); + + ctx.Ebp = _ebp; + ctx.Eip = _eip; + ctx.Esp = _esp; + ctx.ContextFlags = CONTEXT_CONTROL; +#endif + + Logger_AbortCommon(result, raw_msg, &ctx); +} +#if _MSC_VER +#pragma optimize ("", on) +#endif +#endif +#ifdef CC_BUILD_POSIX +static void Logger_SignalHandler(int sig, siginfo_t* info, void* ctx) { + String msg; char msgBuffer[STRING_SIZE * 2 + 1]; + int type, code; + uintptr_t addr; + + /* Uninstall handler to avoid chance of infinite loop */ + signal(SIGSEGV, SIG_DFL); + signal(SIGBUS, SIG_DFL); + signal(SIGILL, SIG_DFL); + signal(SIGABRT, SIG_DFL); + signal(SIGFPE, SIG_DFL); + + type = info->si_signo; + code = info->si_code; + addr = (uintptr_t)info->si_addr; + + String_InitArray_NT(msg, msgBuffer); + String_Format3(&msg, "Unhandled signal %i (code %i) at 0x%x", &type, &code, &addr); + msg.buffer[msg.length] = '\0'; + + Logger_AbortCommon(0, msg.buffer, ctx); +} + +void Logger_Hook(void) { + struct sigaction sa, old; + sa.sa_sigaction = Logger_SignalHandler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART | SA_SIGINFO; + + sigaction(SIGSEGV, &sa, &old); + sigaction(SIGBUS, &sa, &old); + sigaction(SIGILL, &sa, &old); + sigaction(SIGABRT, &sa, &old); + sigaction(SIGFPE, &sa, &old); +} + +void Logger_Abort2(ReturnCode result, const char* raw_msg) { + ucontext_t ctx; + getcontext(&ctx); + Logger_AbortCommon(result, raw_msg, &ctx); +} +#endif +#ifdef CC_BUILD_WEB +void Logger_Hook(void) { } +void Logger_Abort2(ReturnCode result, const char* raw_msg) { + Logger_AbortCommon(result, raw_msg, NULL); +} +#endif /*########################################################################################################################* *----------------------------------------------------------Common---------------------------------------------------------* *#########################################################################################################################*/ -void Logger_OldWarn(ReturnCode res, const char* place) { - String msg; char msgBuffer[128]; - String_InitArray(msg, msgBuffer); - - String_Format2(&msg, "Error %h when %c", &res, place); - Logger_WarnFunc(&msg); -} - -void Logger_OldWarn2(ReturnCode res, const char* place, const String* path) { - String msg; char msgBuffer[256]; - String_InitArray(msg, msgBuffer); - - String_Format3(&msg, "Error %h when %c '%s'", &res, place, path); - Logger_WarnFunc(&msg); -} - -void Logger_SysWarn(ReturnCode res, const char* place, Logger_DescribeError describeErr) { - String msg; char msgBuffer[256]; - String_InitArray(msg, msgBuffer); - String_Append(&msg, '"'); - - if (describeErr(res, &msg)) { - String_Format2(&msg, "\" (i) error when %c", &res, place); - } else { - String_DeleteAt(&msg, 0); - String_Format2(&msg, "Error %h when %c", &res, place); - } - Logger_WarnFunc(&msg); -} - -void Logger_SysWarn2(ReturnCode res, const char* place, const String* path, Logger_DescribeError describeErr) { - String msg; char msgBuffer[256]; - String_InitArray(msg, msgBuffer); - String_Append(&msg, '"'); - - if (describeErr(res, &msg)) { - String_Format3(&msg, "\" (%i) error when %c '%s'", &res, place, path); - } else { - String_DeleteAt(&msg, 0); - String_Format3(&msg, "Error %h when %c '%s'", &res, place, path); - } - Logger_WarnFunc(&msg); -} - -void Logger_DynamicLibWarn2(ReturnCode res, const char* place, const String* path) { - Logger_SysWarn2(res, place, path, DynamicLib_DescribeError); -} -void Logger_Warn2(ReturnCode res, const char* place, const String* path) { - Logger_SysWarn2(res, place, path, Platform_DescribeError); -} - -void Logger_DialogWarn(const String* msg) { - String dst; char dstBuffer[256]; - String_InitArray_NT(dst, dstBuffer); - - String_AppendString(&dst, msg); - dst.buffer[dst.length] = '\0'; - Window_ShowDialog(Logger_DialogTitle, dst.buffer); -} -const char* Logger_DialogTitle = "Error"; -Logger_DoWarn Logger_WarnFunc = Logger_DialogWarn; - static FileHandle logFile; static struct Stream logStream; static bool logOpen; diff --git a/src/Logger.h b/src/Logger.h index 651b28022..74fa90687 100644 --- a/src/Logger.h +++ b/src/Logger.h @@ -27,6 +27,8 @@ void Logger_SysWarn2(ReturnCode res, const char* place, const String* path, Logg /* Shortcut for Logger_SysWarn2 with DynamicLib_DescribeError */ void Logger_DynamicLibWarn2(ReturnCode res, const char* place, const String* path); +/* Shortcut for Logger_SysWarn with Platform_DescribeError */ +void Logger_Warn(ReturnCode res, const char* place); /* Shortcut for Logger_SysWarn2 with Platform_DescribeError */ void Logger_Warn2(ReturnCode res, const char* place, const String* path); diff --git a/src/Platform.c b/src/Platform.c index 6b9e14c78..ffdc9c587 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -2028,7 +2028,7 @@ void Platform_Init(void) { heap = GetProcessHeap(); res = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (res) Logger_OldWarn(res, "starting WSA"); + if (res) Logger_Warn(res, "starting WSA"); hasDebugger = IsDebuggerPresent(); /* For when user runs from command prompt */ diff --git a/src/Program.c b/src/Program.c index 42ab7a21b..4f2bf5008 100644 --- a/src/Program.c +++ b/src/Program.c @@ -72,14 +72,14 @@ static void Program_SetCurrentDirectory(void) { String_InitArray(path, pathBuffer); res = Process_GetExePath(&path); - if (res) { Logger_OldWarn(res, "getting exe path"); return; } + if (res) { Logger_Warn(res, "getting exe path"); return; } /* get rid of filename at end of directory */ for (i = path.length - 1; i >= 0; i--, path.length--) { if (path.buffer[i] == '/' || path.buffer[i] == '\\') break; } res = Platform_SetCurrentDirectory(&path); - if (res) { Logger_OldWarn(res, "setting current directory"); return; } + if (res) { Logger_Warn(res, "setting current directory"); return; } #endif } diff --git a/src/Resources.c b/src/Resources.c index 0b49ee913..af15952d2 100644 --- a/src/Resources.c +++ b/src/Resources.c @@ -83,13 +83,13 @@ static void Resources_CheckTextures(void) { if (!File_Exists(&path)) return; res = Stream_OpenFile(&stream, &path); - if (res) { Logger_OldWarn(res, "checking default.zip"); return; } + if (res) { Logger_Warn(res, "checking default.zip"); return; } Zip_Init(&state, &stream); state.SelectEntry = Resources_SelectZipEntry; res = Zip_Extract(&state); stream.Close(&stream); - if (res) Logger_OldWarn(res, "inspecting default.zip"); + if (res) Logger_Warn(res, "inspecting default.zip"); /* if somehow have say "gui.png", "GUI.png" */ Textures_AllExist = texturesFound >= Array_Elems(Resources_Textures); @@ -558,13 +558,13 @@ static void TexPatcher_MakeDefaultZip(void) { res = Stream_CreateFile(&s, &path); if (res) { - Logger_OldWarn(res, "creating default.zip"); + Logger_Warn(res, "creating default.zip"); } else { res = TexPatcher_WriteEntries(&s); - if (res) Logger_OldWarn(res, "making default.zip"); + if (res) Logger_Warn(res, "making default.zip"); res = s.Close(&s); - if (res) Logger_OldWarn(res, "closing default.zip"); + if (res) Logger_Warn(res, "closing default.zip"); } for (i = 0; i < Array_Elems(Resources_Files); i++) { @@ -585,9 +585,9 @@ static void SoundPatcher_FixupHeader(struct Stream* s, struct VorbisState* ctx) ReturnCode res; res = s->Length(s, &length); - if (res) { Logger_OldWarn(res, "getting .wav length"); return; } + if (res) { Logger_Warn(res, "getting .wav length"); return; } res = s->Seek(s, 0); - if (res) { Logger_OldWarn(res, "seeking to .wav start"); return; } + if (res) { Logger_Warn(res, "seeking to .wav start"); return; } Stream_SetU32_BE(&header[0], WAV_FourCC('R','I','F','F')); Stream_SetU32_LE(&header[4], length - 8); @@ -605,7 +605,7 @@ static void SoundPatcher_FixupHeader(struct Stream* s, struct VorbisState* ctx) Stream_SetU32_LE(&header[40], length - sizeof(header)); res = Stream_Write(s, header, sizeof(header)); - if (res) Logger_OldWarn(res, "fixing .wav header"); + if (res) Logger_Warn(res, "fixing .wav header"); } static void SoundPatcher_DecodeAudio(struct Stream* s, struct VorbisState* ctx) { @@ -615,21 +615,21 @@ static void SoundPatcher_DecodeAudio(struct Stream* s, struct VorbisState* ctx) /* ctx is all 0, so reuse it here for header */ res = Stream_Write(s, ctx, 44); - if (res) { Logger_OldWarn(res, "writing .wav header"); return; } + if (res) { Logger_Warn(res, "writing .wav header"); return; } res = Vorbis_DecodeHeaders(ctx); - if (res) { Logger_OldWarn(res, "decoding .ogg header"); return; } + if (res) { Logger_Warn(res, "decoding .ogg header"); return; } samples = Mem_Alloc(ctx->BlockSizes[1] * ctx->Channels, 2, ".ogg samples"); for (;;) { res = Vorbis_DecodeFrame(ctx); if (res == ERR_END_OF_STREAM) break; - if (res) { Logger_OldWarn(res, "decoding .ogg"); break; } + if (res) { Logger_Warn(res, "decoding .ogg"); break; } count = Vorbis_OutputFrame(ctx, samples); /* TODO: Do we need to account for big endian */ res = Stream_Write(s, samples, count * 2); - if (res) { Logger_OldWarn(res, "writing samples"); break; } + if (res) { Logger_Warn(res, "writing samples"); break; } } Mem_Free(samples); } @@ -646,7 +646,7 @@ static void SoundPatcher_Save(struct ResourceSound* sound, struct HttpRequest* r String_Format1(&path, "audio/%c.wav", sound->Name); res = Stream_CreateFile(&dst, &path); - if (res) { Logger_OldWarn(res, "creating .wav file"); return; } + if (res) { Logger_Warn(res, "creating .wav file"); return; } Ogg_MakeStream(&ogg, buffer, &src); ctx.Source = &ogg; @@ -655,7 +655,7 @@ static void SoundPatcher_Save(struct ResourceSound* sound, struct HttpRequest* r SoundPatcher_FixupHeader(&dst, &ctx); res = dst.Close(&dst); - if (res) Logger_OldWarn(res, "closing .wav file"); + if (res) Logger_Warn(res, "closing .wav file"); } static void MusicPatcher_Save(struct ResourceMusic* music, struct HttpRequest* req) { @@ -666,7 +666,7 @@ static void MusicPatcher_Save(struct ResourceMusic* music, struct HttpRequest* r String_Format1(&path, "audio/%c", music->Name); res = Stream_WriteAllTo(&path, req->Data, req->Size); - if (res) Logger_OldWarn(res, "saving music file"); + if (res) Logger_Warn(res, "saving music file"); } diff --git a/src/String.c b/src/String.c index 00990d561..f7b139c99 100644 --- a/src/String.c +++ b/src/String.c @@ -74,6 +74,17 @@ int String_UNSAFE_Split(STRING_REF const String* str, char c, String* subs, int return count; } +CC_API void String_UNSAFE_SplitBy(STRING_REF String* str, char c, String* part) { + int idx = String_IndexOf(str, c); + if (idx == -1) { + *part = *str; + *str = String_Empty; + } else { + *part = String_UNSAFE_Substring(str, 0, idx); idx++; + *str = String_UNSAFE_SubstringAt(str, idx); + } +} + bool String_UNSAFE_Separate(STRING_REF const String* str, char c, String* key, String* value) { int idx = String_IndexOf(str, c); if (idx == -1) { diff --git a/src/String.h b/src/String.h index 84182033f..ef876fcee 100644 --- a/src/String.h +++ b/src/String.h @@ -64,6 +64,9 @@ CC_API String String_UNSAFE_Substring(STRING_REF const String* str, int offset, /* UNSAFE: Splits a string of the form [str1][c][str2][c][str3].. into substrings. */ /* e.g., "abc:id:xyz" becomes "abc","id","xyz" */ CC_API int String_UNSAFE_Split(STRING_REF const String* str, char c, String* subs, int maxSubs); +/* UNSAFE: Splits a string of the form [part][c][rest], returning whether [c] was found or not. */ +/* NOTE: This is intended to be repeatedly called until str->length is 0. (unbounded String_UNSAFE_Split) */ +CC_API void String_UNSAFE_SplitBy(STRING_REF String* str, char c, String* part); /* UNSAFE: Splits a string of the form [key][c][value] into two substrings. */ /* e.g., "allowed =true" becomes "allowed" and "true", and excludes the space. */ /* If c is not found, sets key to str and value to String_Empty, returns false. */ diff --git a/src/Window.c b/src/Window.c index 3062d167c..b6e017c5b 100644 --- a/src/Window.c +++ b/src/Window.c @@ -1462,16 +1462,12 @@ static void X11Textbox_Measure(X11Textbox* t, XFontStruct* font) { } static void X11Textbox_Draw(X11Textbox* t, X11Window* w) { - String str = String_FromReadonly(t->Text); + String str = String_FromReadonly(t->Text), line; int y = t->Y + t->LineHeight - t->Descent; /* TODO: is -Descent even right? */ - int end, len; - for (end = 0; end >= 0; y += t->LineHeight) { - end = String_IndexOf(&str, '\n'); - len = end == -1 ? str.length : end; - - XDrawString(dpy, w->win, w->gc, t->X, y, str.buffer, len); - if (end >= 0) str = String_UNSAFE_SubstringAt(&str, end + 1); + while (str.length) { + String_UNSAFE_SplitBy(&str, '\n', &line); + XDrawString(dpy, w->win, w->gc, t->X, y, line.buffer, line.length); } }