/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiSource Program Utilities * Copyright (C) 1998 AbiSource, Inc. * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef UT_ASSERT_H #define UT_ASSERT_H #ifdef HAVE_CONFIG_H #include "config.h" #endif // TODO move these declarations into platform directories. #if (defined (WIN32) || defined (_WIN32) || defined (_WIN64)) // The 'cool' win32 assert, at least with VC6, corrups memory (probably calling sprintf on // a static buffer without checking bounds), so we implement our own assert dialog, which // is even cooler. TF #include "ut_types.h" #ifdef NDEBUG # define UT_ASSERT(x) #else // This function is implemented in ut_Win32Misc.cpp. It is not declared in any header file (it is // only to be referenced from here and we want to reduce the files we include here to a // bare minimum for performance reasons, as this file gets included from pretty much // everywhere). extern int ABI_EXPORT UT_Win32ThrowAssert(const char * pCondition, const char * pFile, int iLine, int iCount); // The best way of stepping into debugger is by generating the appropriate interupt // instruction, so if we are on Intel x86, we will issue int 3. If we are not on x86, we // will use the win32 DebugBreak() function (the disadvantage of that is that the // execution is interupted not in our code, but in one of the system libs, so you have to // step out of that system function to get into our code; its rather non-intuitive. # undef UT_DEBUG_BREAK // I am not sure which is the standard GCC macro for the x86 platform; we are supposed to // be able to get all the predefined macros by running 'cpp -dM' but it would not work on // my cygwin # if defined(__GNUC__) && (defined(_X86) || defined(__i386) || defined(i386)) // Inline assembly for GCC on x86 # define UT_DEBUG_BREAK asm("int3"); # elif defined(__GNUC__) && (defined(__ia64) || defined(ia64)) # error "This branch has not been tested." // On Itanium we use the intrinsic function __break(); defined in ia64intrin.h // I am not sure whether we need to tell the compiler this one is intrinsic (MSVC // uses a #pragma for this void __break(int); # define UT_DEBUG_BREAK __break(0x80016); # elif defined(_MSC_VER) && defined(_M_IX86) // inline assmebly for MSVC on x86 # define UT_DEBUG_BREAK _asm {int 3} # elif defined(_MSC_VER) && (defined(_M_IA64) || defined(_M_AMD64)) # error "This branch has not been tested." // On Itanium we use the intrinsic function __break(); // I assume this will also work for AMD64, but I am not 100% sure void __break(int); // this forces __break() to be generated as inline code (see MSDN) # pragma intrinsic (__break) # define UT_DEBUG_BREAK __break(0x80016); # endif # ifndef UT_DEBUG_BREAK // Some compiler/architecture for which we do not know how to generate inline assembly to pass // control to the debugger; we use win32s DebugBreak(). // // TODO !!! This currently does not work; if someone one day wants to build AW on non-x86 // win32 architecture, they will need to fix this (including from here, which // is what would work, screws up things in MS Word importer, because the wv library // redefines some of the win32 structures; but we probably do not want to include // windows.h from here anyway because of the overhead -- ut_assert.h gets included in // almost everything.). Really, we want to do something similar as we do for x86. # error "Proper implementation needed for this compiler/architecture" # ifndef _WINBASE_ __declspec(dllimport) void __stdcall DebugBreak(void); # endif /* ifdef _WINBASE_ */ # define UT_DEBUG_BREAK DebugBreak(); # endif /* ifndef UT_DEBUG_BREAK */ // We want to track the number of times we have been through this assert and have the // option of disabling this assert for the rest of the session; we use the __iCount and // __bOnceOnly vars for this (this adds a few bytes to the code and footprint, but on // large scale of things, this is quite negligible for the debug build). #define UT_ASSERT(x) \ { \ static bool __bOnceOnly = false; \ static long __iCount = 0; \ if(!__bOnceOnly && !(x)) \ { \ __iCount++; \ int __iRet = UT_Win32ThrowAssert(#x,__FILE__, __LINE__, __iCount); \ if(__iRet == 0) \ { \ UT_DEBUG_BREAK \ } \ else if(__iRet < 0) \ { \ __bOnceOnly = true; \ } \ } \ } #endif // ifdef NDEBUG #else // A Unix variant, possibly Gnome. # ifdef NDEBUG // When NDEBUG is defined, assert() does nothing. // So we let the system header files take care of it. # if defined(TOOLKIT_COCOA) // Please keep the "/**/" to stop MSVC dependency generator complaining. # include /**/ "xap_CocoaAssert.h" # define UT_ASSERT(expr) \ ((void) ((expr) || \ (XAP_CocoaAssertMsg(#expr, \ __FILE__, __LINE__), \ 0))) # else # include # define UT_ASSERT assert # endif # else // Otherwise, we want a slighly modified behavior. // We'd like assert() to ask us before crashing. // We treat asserts as logic flaws, which are sometimes // recoverable, but that should be noted. # include // Please keep the "/**/" to stop MSVC dependency generator complaining. # include /**/ "ut_unixAssert.h" # define UT_ASSERT(expr) \ { \ static bool __bOnceOnly = false; \ if (!__bOnceOnly && !(expr)) \ if (UT_UnixAssertMsg(#expr, __FILE__, __LINE__) == -1) \ __bOnceOnly = true; \ } # endif #endif /*! * This part is not implemented. Same as UT_TODO */ #define UT_NOT_IMPLEMENTED 0 /*! * This really shouldn't happen */ #define UT_SHOULD_NOT_HAPPEN 0 /*! * This part is left TODO */ #define UT_TODO 0 /*! * This line of code should not be reached */ #define UT_NOT_REACHED 0 /*! * This line of code should not be reached */ #define UT_ASSERT_NOT_REACHED() UT_ASSERT(UT_NOT_REACHED) /*! * Trigger a debug assertion, but let the normal flow of code progress */ #define UT_ASSERT_HARMLESS(cond) UT_ASSERT(cond) /*! * Just return from a function if this condition fails */ #define UT_return_if_fail(cond) if (!(cond)) { UT_ASSERT(cond); return; } /*! * Just return this value from a function if this condition fails */ #define UT_return_val_if_fail(cond, val) if (!(cond)) { UT_ASSERT(cond); return (val); } /*! * Throw if this condition fails */ #define UT_throw_if_fail(cond, val) if (!(cond)) { UT_ASSERT(cond); throw val; } /*! * Continue if this condition fails */ #define UT_continue_if_fail(cond) if (!(cond)) { UT_ASSERT(cond); continue; } #endif /* UT_ASSERT_H */