mxwcore-wotlk/deps/g3dlite/source/debugAssert.cpp

392 lines
9.9 KiB
C++

/**
@file debugAssert.cpp
Windows implementation of assertion routines.
@maintainer Morgan McGuire, graphics3d.com
@created 2001-08-26
@edited 2009-06-02
*/
#include "G3D/debugAssert.h"
#include "G3D/platform.h"
#ifdef G3D_WINDOWS
#include <tchar.h>
#endif
#include "G3D/format.h"
#include "G3D/prompt.h"
#include <string>
#include "G3D/debugPrintf.h"
#include "G3D/Log.h"
#include <cstdlib>
#ifdef _MSC_VER
// disable: "C++ exception handler used"
# pragma warning (push)
# pragma warning (disable : 4530)
#endif
using namespace std;
namespace G3D { namespace _internal {
ConsolePrintHook _consolePrintHook;
AssertionHook _debugHook = _handleDebugAssert_;
AssertionHook _failureHook = _handleErrorCheck_;
#ifdef G3D_LINUX
#if 0 /* G3DFIX: Disabled to avoid requirement for X11 libraries */
Display* x11Display = NULL;
Window x11Window = 0;
#endif
#endif
#ifdef G3D_WINDOWS
static void postToClipboard(const char *text) {
if (OpenClipboard(NULL)) {
HGLOBAL hMem = GlobalAlloc(GHND | GMEM_DDESHARE, strlen(text) + 1);
if (hMem) {
char *pMem = (char*)GlobalLock(hMem);
strcpy(pMem, text);
GlobalUnlock(hMem);
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
}
CloseClipboard();
GlobalFree(hMem);
}
}
#endif
/**
outTitle should be set before the call
*/
static void createErrorMessage(
const char* expression,
const std::string& message,
const char* filename,
int lineNumber,
std::string& outTitle,
std::string& outMessage) {
std::string le = "";
const char* newline = "\n";
#ifdef G3D_WINDOWS
newline = "\r\n";
// The last error value. (Which is preserved across the call).
DWORD lastErr = GetLastError();
// The decoded message from FormatMessage
LPTSTR formatMsg = NULL;
if (NULL == formatMsg) {
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
lastErr,
0,
(LPTSTR)&formatMsg,
0,
NULL);
}
// Make sure the message got translated into something.
LPTSTR realLastErr;
if (NULL != formatMsg) {
realLastErr = formatMsg;
} else {
realLastErr = LPTSTR(_T("Last error code does not exist."));
}
if (lastErr != 0) {
le = G3D::format("Last Error (0x%08X): %s\r\n\r\n", lastErr, (LPCSTR)realLastErr);
}
// Get rid of the allocated memory from FormatMessage.
if (NULL != formatMsg) {
LocalFree((LPVOID)formatMsg);
}
char modulePath[MAX_PATH];
GetModuleFileNameA(NULL, modulePath, MAX_PATH);
const char* moduleName = strrchr(modulePath, '\\');
outTitle = outTitle + string(" - ") + string(moduleName ? (moduleName + 1) : modulePath);
#else
(void)outTitle;
#endif
// Build the message.
outMessage =
G3D::format("%s%s%sExpression: %s%s%s:%d%s%s%s",
message.c_str(), newline, newline, expression, newline,
filename, lineNumber, newline, newline, le.c_str());
}
bool _handleDebugAssert_(
const char* expression,
const std::string& message,
const char* filename,
int lineNumber,
bool useGuiPrompt) {
std::string dialogTitle = "Assertion Failure";
std::string dialogText = "";
createErrorMessage(expression, message, filename, lineNumber, dialogTitle, dialogText);
#ifdef G3D_WINDOWS
DWORD lastErr = GetLastError();
postToClipboard(dialogText.c_str());
debugPrintf("\n%s\n", dialogText.c_str());
#endif
const int cBreak = 0;
const int cIgnore = 1;
const int cAbort = 2;
static const char* choices[] = {"Debug", "Ignore", "Exit"};
// Log the error
Log::common()->print(std::string("\n**************************\n\n") + dialogTitle + "\n" + dialogText);
int result = G3D::prompt(dialogTitle.c_str(), dialogText.c_str(), (const char**)choices, 3, useGuiPrompt);
# ifdef G3D_WINDOWS
// Put the incoming last error back.
SetLastError(lastErr);
# endif
switch (result) {
// -1 shouldn't actually occur because it means
// that we're in release mode.
case -1:
case cBreak:
return true;
break;
case cIgnore:
return false;
break;
case cAbort:
exit(-1);
break;
}
// Should never get here
return false;
}
bool _handleErrorCheck_(
const char* expression,
const std::string& message,
const char* filename,
int lineNumber,
bool useGuiPrompt) {
std::string dialogTitle = "Critical Error";
std::string dialogText = "";
createErrorMessage(expression, message, filename, lineNumber, dialogTitle, dialogText);
// Log the error
Log::common()->print(std::string("\n**************************\n\n") + dialogTitle + "\n" + dialogText);
#ifdef G3D_WINDOWS
DWORD lastErr = GetLastError();
(void)lastErr;
postToClipboard(dialogText.c_str());
debugPrintf("\n%s\n", dialogText.c_str());
#endif
static const char* choices[] = {"Ok"};
const std::string& m =
std::string("An internal error has occured in this program and it will now close. "
"The specific error is below. More information has been saved in \"") +
Log::getCommonLogFilename() + "\".\n\n" + dialogText;
int result = G3D::prompt("Error", m.c_str(), (const char**)choices, 1, useGuiPrompt);
(void)result;
return true;
}
#ifdef G3D_WINDOWS
static HCURSOR oldCursor;
static RECT oldCursorRect;
static POINT oldCursorPos;
static int oldShowCursorCount;
#endif
void _releaseInputGrab_() {
#ifdef G3D_WINDOWS
GetCursorPos(&oldCursorPos);
// Stop hiding the cursor if the application hid it.
oldShowCursorCount = ShowCursor(true) - 1;
if (oldShowCursorCount < -1) {
for (int c = oldShowCursorCount; c < -1; ++c) {
ShowCursor(true);
}
}
// Set the default cursor in case the application
// set the cursor to NULL.
oldCursor = GetCursor();
SetCursor(LoadCursor(NULL, IDC_ARROW));
// Allow the cursor full access to the screen
GetClipCursor(&oldCursorRect);
ClipCursor(NULL);
#elif defined(G3D_LINUX)
#if 0 /* G3DFIX: Disabled to avoid requirement for X11 libraries */
if (x11Display != NULL) {
XUngrabPointer(x11Display, CurrentTime);
XUngrabKeyboard(x11Display, CurrentTime);
if (x11Window != 0) {
//XUndefineCursor(x11Display, x11Window);
// TODO: Note that we leak this cursor; it should be
// freed in the restore code.
Cursor c = XCreateFontCursor(x11Display, 68);
XDefineCursor(x11Display, x11Window, c);
}
XSync(x11Display, false);
XAllowEvents(x11Display, AsyncPointer, CurrentTime);
XFlush(x11Display);
}
#endif
#elif defined(G3D_OSX)
// TODO: OS X
#endif
}
void _restoreInputGrab_() {
#ifdef G3D_WINDOWS
// Restore the old clipping region
ClipCursor(&oldCursorRect);
SetCursorPos(oldCursorPos.x, oldCursorPos.y);
// Restore the old cursor
SetCursor(oldCursor);
// Restore old visibility count
if (oldShowCursorCount < 0) {
for (int c = 0; c > oldShowCursorCount; --c) {
ShowCursor(false);
}
}
#elif defined(G3D_LINUX)
// TODO: Linux
#elif defined(G3D_OSX)
// TODO: OS X
#endif
}
}; // internal namespace
void setAssertionHook(AssertionHook hook) {
G3D::_internal::_debugHook = hook;
}
AssertionHook assertionHook() {
return G3D::_internal::_debugHook;
}
void setFailureHook(AssertionHook hook) {
G3D::_internal::_failureHook = hook;
}
AssertionHook failureHook() {
return G3D::_internal::_failureHook;
}
void setConsolePrintHook(ConsolePrintHook h) {
G3D::_internal::_consolePrintHook = h;
}
ConsolePrintHook consolePrintHook() {
return G3D::_internal::_consolePrintHook;
}
std::string __cdecl debugPrint(const std::string& s) {
# ifdef G3D_WINDOWS
const int MAX_STRING_LEN = 1024;
// Windows can't handle really long strings sent to
// the console, so we break the string.
if (s.size() < MAX_STRING_LEN) {
OutputDebugStringA(s.c_str());
} else {
for (unsigned int i = 0; i < s.size(); i += MAX_STRING_LEN) {
std::string sub = s.substr(i, MAX_STRING_LEN);
OutputDebugStringA(sub.c_str());
}
}
# else
fprintf(stderr, "%s", s.c_str());
fflush(stderr);
# endif
return s;
}
std::string __cdecl debugPrintf(const char* fmt ...) {
va_list argList;
va_start(argList, fmt);
std::string s = G3D::vformat(fmt, argList);
va_end(argList);
return debugPrint(s);
// return debugPrint(consolePrint(s));
}
std::string consolePrint(const std::string& s) {
FILE* L = Log::common()->getFile();
fprintf(L, "%s", s.c_str());
if (consolePrintHook()) {
consolePrintHook()(s);
}
fflush(L);
return s;
}
std::string __cdecl consolePrintf(const char* fmt ...) {
va_list argList;
va_start(argList, fmt);
std::string s = G3D::vformat(fmt, argList);
va_end(argList);
return consolePrint(s);
}
} // namespace
#ifdef _MSC_VER
# pragma warning (pop)
#endif