mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Initial commit of ResInsight version 0.4.8
This commit is contained in:
462
VisualizationModules/LibCore/cvfAssert.cpp
Normal file
462
VisualizationModules/LibCore/cvfAssert.cpp
Normal file
@@ -0,0 +1,462 @@
|
||||
//##################################################################################################
|
||||
//
|
||||
// Custom Visualization Core library
|
||||
// Copyright (C) 2011-2012 Ceetron AS
|
||||
//
|
||||
// This library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
||||
// for more details.
|
||||
//
|
||||
//##################################################################################################
|
||||
|
||||
#include "cvfBase.h"
|
||||
#include "cvfAssert.h"
|
||||
#include "cvfSystem.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4668)
|
||||
#include <windows.h>
|
||||
#pragma warning (pop)
|
||||
#include <io.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
namespace cvf {
|
||||
|
||||
|
||||
// User actions (interactive responses)
|
||||
static const int USERACTION_CONTINUE = 0;
|
||||
static const int USERACTION_DEBUGBREAK = 1;
|
||||
static const int USERACTION_ABORT = 2;
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// \class cvf::AssertHandler
|
||||
/// \ingroup Core
|
||||
///
|
||||
/// Base class for assert handlers
|
||||
///
|
||||
//==================================================================================================
|
||||
class AssertHandler
|
||||
{
|
||||
public:
|
||||
virtual ~AssertHandler() {}
|
||||
virtual Assert::FailAction handleAssert(const char* fileName, int lineNumber, const char* expr, const char* msg) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// \class cvf::AssertHandlerConsole
|
||||
/// \ingroup Core
|
||||
///
|
||||
/// Assert handler for basic assert output to console
|
||||
///
|
||||
//==================================================================================================
|
||||
class AssertHandlerConsole : public AssertHandler
|
||||
{
|
||||
public:
|
||||
virtual Assert::FailAction handleAssert(const char* fileName, int lineNumber, const char* expr, const char* msg);
|
||||
|
||||
private:
|
||||
static void reportToConsole(const char* fileName, int lineNumber, const char* expr, const char* msg);
|
||||
static int askForUserActionUsingConsole();
|
||||
#ifdef WIN32
|
||||
static void winCreateConsoleAndRedirectIO(bool redirectInput);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Show report of a failed assert in console and abort execution
|
||||
///
|
||||
/// On Windows, a console will be created if one doesn't exist (GUI applications)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
Assert::FailAction AssertHandlerConsole::handleAssert(const char* fileName, int lineNumber, const char* expr, const char* msg)
|
||||
{
|
||||
// Just shows assert message in console.
|
||||
// Does the job on both Windows and Linux (creates a console on Windows if one doesn't exist)
|
||||
reportToConsole(fileName, lineNumber, expr, msg);
|
||||
|
||||
abort();
|
||||
|
||||
// Shouldn't really matter since we always abort
|
||||
return Assert::CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void AssertHandlerConsole::reportToConsole(const char* fileName, int lineNumber, const char* expr, const char* msg)
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Make sure we have a console (applicable to Windows GUI applications)
|
||||
winCreateConsoleAndRedirectIO(false);
|
||||
#endif
|
||||
|
||||
std::cerr << "Assertion failed:";
|
||||
|
||||
if (expr)
|
||||
{
|
||||
std::cerr << " (" << expr << ")";
|
||||
}
|
||||
|
||||
if (msg)
|
||||
{
|
||||
std::cerr << " '" << msg << "'";
|
||||
}
|
||||
|
||||
if (expr || msg)
|
||||
{
|
||||
std::cerr << ",";
|
||||
}
|
||||
|
||||
std::cerr << " file " << fileName << ", line " << lineNumber << std::endl;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Ask for user action using console input
|
||||
///
|
||||
/// \return One of the USERACTION_ constants
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int AssertHandlerConsole::askForUserActionUsingConsole()
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Make sure we have a console (applicable to Windows GUI applications)
|
||||
// Also ensures that input is redirected
|
||||
winCreateConsoleAndRedirectIO(true);
|
||||
#endif
|
||||
|
||||
// Let abort be the default choice
|
||||
#ifdef WIN32
|
||||
std::cerr << "Choose action: [A]bort, [R]etry (debug) or [I]gnore: default [A]\n";
|
||||
#else
|
||||
std::cerr << "Choose action: [A]bort or [I]gnore: default [A]\n";
|
||||
#endif
|
||||
|
||||
// Reset failstate, just in case.
|
||||
std::cin.clear();
|
||||
|
||||
std::string line;
|
||||
while (std::getline(std::cin, line))
|
||||
{
|
||||
int ch = 0;
|
||||
if (!std::cin.fail() && line.length() == 1)
|
||||
{
|
||||
ch = tolower(line[0]);
|
||||
}
|
||||
|
||||
if (ch == 'i')
|
||||
{
|
||||
return USERACTION_CONTINUE;
|
||||
}
|
||||
#ifdef WIN32
|
||||
else if (ch == 'r')
|
||||
{
|
||||
return USERACTION_DEBUGBREAK;
|
||||
}
|
||||
#endif
|
||||
else if (ch == 'a' || line.length() == 0)
|
||||
{
|
||||
return USERACTION_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
return USERACTION_ABORT;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Creates a console and redirects I/O from/to it (Windows only)
|
||||
///
|
||||
/// \param redirectInput If true, input will also be redirected.
|
||||
///
|
||||
/// Function is useful for Windows GUI applications. Allocates a console if it doesn't exist and
|
||||
/// then redirects output to the console. Also redirects input if \a redirectInput is true
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
#ifdef WIN32
|
||||
void AssertHandlerConsole::winCreateConsoleAndRedirectIO(bool redirectInput)
|
||||
{
|
||||
// Allocate a new console for this app
|
||||
// Only one console can be associated with an app, so should fail if a console is already present.
|
||||
AllocConsole();
|
||||
|
||||
|
||||
bool redirStdOut = true;
|
||||
bool redirStdErr = true;
|
||||
bool redirStdIn = redirectInput;
|
||||
|
||||
if (redirStdOut)
|
||||
{
|
||||
HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
|
||||
FILE* fp = _fdopen(fileDescriptor, "w");
|
||||
|
||||
*stdout = *fp;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
}
|
||||
|
||||
if (redirStdErr)
|
||||
{
|
||||
HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
|
||||
FILE* fp = _fdopen(fileDescriptor, "w");
|
||||
|
||||
*stderr = *fp;
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
}
|
||||
|
||||
if (redirStdIn)
|
||||
{
|
||||
HANDLE stdHandle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
|
||||
FILE* fp = _fdopen(fileDescriptor, "r");
|
||||
|
||||
*stdin = *fp;
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
}
|
||||
|
||||
|
||||
// Make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
|
||||
std::ios::sync_with_stdio();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// \class cvf::AssertHandlerWinDialog
|
||||
/// \ingroup Core
|
||||
///
|
||||
/// Assert handler for Windows, using a dialog with interaction
|
||||
///
|
||||
//==================================================================================================
|
||||
#ifdef WIN32
|
||||
class AssertHandlerWinDialog : public AssertHandler
|
||||
{
|
||||
public:
|
||||
virtual Assert::FailAction handleAssert(const char* fileName, int lineNumber, const char* expr, const char* msg);
|
||||
|
||||
private:
|
||||
static int handleUsingDialog(const char* fileName, int lineNumber, const char* expr, const char* msg);
|
||||
#ifdef _DEBUG
|
||||
static int handleUsingCrtDbgReport(const char* fileName, int lineNumber, const char* expr, const char* msg);
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
#ifdef WIN32
|
||||
Assert::FailAction AssertHandlerWinDialog::handleAssert(const char* fileName, int lineNumber, const char* expr, const char* msg)
|
||||
{
|
||||
//int retVal = handleUsingCrtDbgReport(fileName, lineNumber, expr, msg);
|
||||
int retVal = handleUsingDialog(fileName, lineNumber, expr, msg);
|
||||
|
||||
if (retVal == USERACTION_CONTINUE)
|
||||
{
|
||||
return Assert::CONTINUE;
|
||||
}
|
||||
else if (retVal == USERACTION_DEBUGBREAK)
|
||||
{
|
||||
return Assert::DEBUGBREAK;
|
||||
}
|
||||
else if (retVal == USERACTION_ABORT)
|
||||
{
|
||||
// From __crtMessageWindow() in response to user clicking abort button
|
||||
// Note that it is better NOT to call abort() here, because the default implementation of abort() will call Watson
|
||||
// raise abort signal
|
||||
raise(SIGABRT);
|
||||
|
||||
// We usually won't get here, but it's possible that SIGABRT was ignored.
|
||||
// So exit the program anyway.
|
||||
_exit(3);
|
||||
}
|
||||
|
||||
// Shouldn't be getting here
|
||||
abort();
|
||||
return Assert::CONTINUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Shows message in interactive dialog and lets user choose how to proceed
|
||||
///
|
||||
/// \return Returns one of the USERACTION_ constants depending on which button the user chooses.
|
||||
///
|
||||
/// Compared to the handleUsingCrtDbgReport() function, this function will also work in release builds
|
||||
/// As opposed to the handleUsingCrtDbgReport(), this function will not call abort, but will return
|
||||
/// USERACTION_ABORT instead.
|
||||
///
|
||||
/// \todo Must add code to handle case where new assert is triggered while handling an assert
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
#ifdef WIN32
|
||||
int AssertHandlerWinDialog::handleUsingDialog(const char* fileName, int lineNumber, const char* expr, const char* msg)
|
||||
{
|
||||
char szMsgBuf[2048];
|
||||
|
||||
System::strcpy(szMsgBuf, sizeof(szMsgBuf), "Assertion failed\n");
|
||||
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), "\nFile: ");
|
||||
if (fileName)
|
||||
{
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), fileName);
|
||||
}
|
||||
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), "\nLine: ");
|
||||
if (lineNumber >= 0)
|
||||
{
|
||||
char szLinNumBuf[20];
|
||||
System::sprintf(szLinNumBuf, sizeof(szLinNumBuf), "%d", lineNumber);
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), szLinNumBuf);
|
||||
}
|
||||
|
||||
|
||||
if (expr)
|
||||
{
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), "\n\n");
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), "Expression: ");
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), expr);
|
||||
}
|
||||
|
||||
if (msg)
|
||||
{
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), "\n\n");
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), msg);
|
||||
}
|
||||
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), "\n\n(Press Retry to debug application)");
|
||||
|
||||
|
||||
int retVal = ::MessageBoxA(NULL, szMsgBuf, "Assertion Failed", MB_TASKMODAL|MB_ICONHAND|MB_ABORTRETRYIGNORE|MB_SETFOREGROUND);
|
||||
|
||||
if (retVal == IDIGNORE) return USERACTION_CONTINUE;
|
||||
else if (retVal == IDRETRY) return USERACTION_DEBUGBREAK;
|
||||
else return USERACTION_ABORT;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Wrapper function for the CRT _CrtDbgReport() function
|
||||
///
|
||||
/// This function never returns if the user chooses 'Abort'
|
||||
/// Note that the underlying function is only available in debug builds
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
#if defined WIN32 && defined _DEBUG
|
||||
int AssertHandlerWinDialog::handleUsingCrtDbgReport(const char* fileName, int lineNumber, const char* expr, const char* msg)
|
||||
{
|
||||
// Create message combining expression and message
|
||||
char szMsgBuf[2048];
|
||||
szMsgBuf[0] = '\0';
|
||||
|
||||
if (expr)
|
||||
{
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), expr);
|
||||
}
|
||||
|
||||
if (msg)
|
||||
{
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), "\n");
|
||||
System::strcat(szMsgBuf, sizeof(szMsgBuf), msg);
|
||||
}
|
||||
|
||||
int retVal = _CrtDbgReport(_CRT_ASSERT, fileName, lineNumber, NULL, szMsgBuf);
|
||||
|
||||
if (retVal == 0) return USERACTION_CONTINUE;
|
||||
else if (retVal == 1) return USERACTION_DEBUGBREAK;
|
||||
else return USERACTION_ABORT;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// \class cvf::Assert
|
||||
/// \ingroup Core
|
||||
///
|
||||
/// Helper class to customize assert
|
||||
///
|
||||
//==================================================================================================
|
||||
|
||||
#ifdef WIN32
|
||||
AssertHandler* Assert::sm_handler = new AssertHandlerWinDialog;
|
||||
#else
|
||||
AssertHandler* Assert::sm_handler = new AssertHandlerConsole;
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void Assert::setReportMode(ReportMode reportMode)
|
||||
{
|
||||
#ifndef WIN32
|
||||
if (reportMode == INTERACTIVE_DIALOG) return;
|
||||
#endif
|
||||
|
||||
delete sm_handler;
|
||||
sm_handler = NULL;
|
||||
|
||||
if (reportMode == CONSOLE)
|
||||
{
|
||||
sm_handler = new AssertHandlerConsole;
|
||||
}
|
||||
#ifdef WIN32
|
||||
else if (reportMode == INTERACTIVE_DIALOG)
|
||||
{
|
||||
sm_handler = new AssertHandlerWinDialog;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Show report of a failed assert
|
||||
///
|
||||
/// If assertions are configured to be interactive, a message box will be shown on Windows and
|
||||
/// the user may opt to ignore or trigger debugging.
|
||||
/// On Linux, or if interactive asserts are disabled, the application will terminate.
|
||||
///
|
||||
/// \todo Add handling of cases where we get another assert while processing the first one AND
|
||||
/// asserts from multiple threads.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
Assert::FailAction Assert::reportFailedAssert(const char* fileName, int lineNumber, const char* expr, const char* msg)
|
||||
{
|
||||
if (sm_handler)
|
||||
{
|
||||
return sm_handler->handleAssert(fileName, lineNumber, expr, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
abort();
|
||||
return CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace cvf
|
||||
|
||||
Reference in New Issue
Block a user