- config: all macros are defined as 1 / 0. testing with #if allows compiler warnings (testing undefined macro) to spot misspelled macros
- debug: add provision for naming threads. allows adding current thread name to log messages and displays their names in the debugger. - replaced various if(err < 0) complain() sequences with new variants of CHECK_ERR (see lib.h) - fixes to mmgr/VC debug alloc enable code - improved h_mgr error reporting (now complains when h_free fails) - US -> UK english (partial) - fix tex_load double-free bug - move win32 mouse cursor code into sysdep - error dialog is now topmost to make sure it's visible (was a problem) - handle WM_QUIT before displaying error dialog (makes sure it's shown) also as in previous 3 revisions. This was SVN commit r2588.
This commit is contained in:
parent
620c65722f
commit
5299dcad86
@ -1,35 +1,71 @@
|
||||
#ifndef CONFIG_H_INCLUDED
|
||||
#define CONFIG_H_INCLUDED
|
||||
|
||||
// the config/have macros are always defined; their values (1 or 0) are
|
||||
// tested with #if instead of #ifdef.
|
||||
// this protects user code from typos such as #ifdef _MSC_VEER, which
|
||||
// would silently remove code. instead, we will at least get "test of
|
||||
// undefined macro" warnings here. not including this header also triggers
|
||||
// such warnings, but won't happen often because we're included from PCH.
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// user-specified configuration choices
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#undef CONFIG_DISABLE_EXCEPTIONS
|
||||
// allow override via compiler settings by checking #ifndef.
|
||||
|
||||
#undef CONFIG_USE_MMGR
|
||||
// enable memory tracking (slow). see mmgr.cpp.
|
||||
#ifndef CONFIG_USE_MMGR
|
||||
# define CONFIG_USE_MMGR 0
|
||||
#endif
|
||||
|
||||
// enable additional debug checks (very slow).
|
||||
#ifndef CONFIG_PARANOIA
|
||||
# define CONFIG_PARANOIA 0
|
||||
#endif
|
||||
|
||||
// try to prevent any exceptions from being thrown - even by the C++
|
||||
// standard library. useful only for performance tests.
|
||||
#ifndef CONFIG_DISABLE_EXCEPTIONS
|
||||
# define CONFIG_DISABLE_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// auto-detect OS and platform via predefined macros
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// get compiler versions with consistent names + format:
|
||||
// (major*100 + minor), or 0 if not present. note that more than
|
||||
// rationale:
|
||||
// - these macros have consistent names and numerical values; using
|
||||
// them saves other code from having to know the obscure predefined macros.
|
||||
// - we'd like to use #if/#elif/#endif chains for e.g. OS_* to allow warning
|
||||
// if none is selected, but there's no good way to #define all inapplicable
|
||||
// settings to 0. doing so up front is hard to maintain and would require
|
||||
// #undef before setting any one to 1. #ifndef afterwards for each setting
|
||||
// is ugly and brittle as well. we therefore use #if/#else/#endif.
|
||||
|
||||
// compiler
|
||||
// 0 if not present, or (major*100 + minor). note that more than
|
||||
// one *_VERSION may be non-zero due to interoperability (e.g. ICC with MSC).
|
||||
// .. ICC
|
||||
#if defined(__INTEL_COMPILER)
|
||||
# define ICC_VERSION __INTEL_COMPILER
|
||||
#else
|
||||
# define ICC_VERSION 0
|
||||
#endif
|
||||
// .. VC
|
||||
#ifdef _MSC_VER
|
||||
# define MSC_VERSION _MSC_VER
|
||||
#else
|
||||
# define MSC_VERSION 0
|
||||
#endif
|
||||
// .. ICC (VC-compatible)
|
||||
#if defined(__INTEL_COMPILER)
|
||||
# define ICC_VERSION __INTEL_COMPILER
|
||||
#else
|
||||
# define ICC_VERSION 0
|
||||
#endif
|
||||
// .. LCC (VC-compatible)
|
||||
#if defined(__LCC__)
|
||||
# define LCC_VERSION __LCC__
|
||||
#else
|
||||
# define LCC_VERSION 0
|
||||
#endif
|
||||
// .. GCC
|
||||
#ifdef __GNUC__
|
||||
# define GCC_VERSION (__GNUC__*100 + __GNUC_MINOR__)
|
||||
@ -37,10 +73,12 @@
|
||||
# define GCC_VERSION 0
|
||||
#endif
|
||||
|
||||
|
||||
// STL
|
||||
// .. pull in the Dinkumware header that defines _CPPLIB_VER
|
||||
// (checked by STL implementation-specific code in debug_stl).
|
||||
// .. Dinkumware
|
||||
#if MSC_VERSION != 0
|
||||
# include <yvals.h>
|
||||
# include <yvals.h> // defines _CPPLIB_VER
|
||||
#endif
|
||||
#if defined(_CPPLIB_VER)
|
||||
# define STL_DINKUMWARE _CPPLIB_VER
|
||||
@ -48,119 +86,190 @@
|
||||
# define STL_DINKUMWARE 0
|
||||
#endif
|
||||
|
||||
|
||||
// OS
|
||||
// .. Windows
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
# define OS_WIN
|
||||
// .. Linux
|
||||
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define OS_LINUX
|
||||
# define OS_UNIX
|
||||
// .. Mac OS X
|
||||
#elif defined(MAC_OS_X
|
||||
# define OS_MACOSX
|
||||
# define OS_UNIX
|
||||
// .. BSD
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# define OS_BSD
|
||||
# define OS_UNIX
|
||||
// .. Solaris
|
||||
#elif defined(SOLARIS)
|
||||
# define OS_SOLARIS
|
||||
# define OS_UNIX
|
||||
// .. BeOS
|
||||
#elif defined(__BEOS__)
|
||||
# define OS_BEOS
|
||||
// .. Mac OS 9 or below
|
||||
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
# define OS_MAC
|
||||
// .. Amiga
|
||||
#elif defined(__amigaos__)
|
||||
# define OS_AMIGA
|
||||
// .. Unix-based
|
||||
#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
|
||||
# define OS_UNIX
|
||||
// .. unknown
|
||||
# define OS_WIN 1
|
||||
#else
|
||||
# error "unknown OS - add define here"
|
||||
# define OS_WIN 0
|
||||
#endif
|
||||
// .. Linux
|
||||
#if defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
#else
|
||||
# define OS_LINUX 0
|
||||
#endif
|
||||
// .. Mac OS X
|
||||
#if defined(MAC_OS_X)
|
||||
# define OS_MACOSX 1
|
||||
#else
|
||||
# define OS_MACOSX 0
|
||||
#endif
|
||||
// .. BSD
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# define OS_BSD 1
|
||||
#else
|
||||
# define OS_BSD 0
|
||||
#endif
|
||||
// .. Solaris
|
||||
#if defined(SOLARIS)
|
||||
# define OS_SOLARIS 1
|
||||
#else
|
||||
# define OS_SOLARIS 0
|
||||
#endif
|
||||
// .. BeOS
|
||||
#if defined(__BEOS__)
|
||||
# define OS_BEOS 1
|
||||
#else
|
||||
# define OS_BEOS 0
|
||||
#endif
|
||||
// .. Mac OS 9 or below
|
||||
#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
# define OS_MAC 1
|
||||
#else
|
||||
# define OS_MAC 0
|
||||
#endif
|
||||
// .. Amiga
|
||||
#if defined(__amigaos__)
|
||||
# define OS_AMIGA 1
|
||||
#else
|
||||
# define OS_AMIGA 0
|
||||
#endif
|
||||
// .. Unix-based
|
||||
#if defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
|
||||
# define OS_UNIX 1
|
||||
#else
|
||||
# define OS_UNIX 0
|
||||
#endif
|
||||
// .. convenience: additionally set OS_UNIX for Unix-based OSes
|
||||
#if OS_LINUX || OS_MACOSX || OS_BSD || OS_SOLARIS
|
||||
# undef OS_UNIX
|
||||
# define OS_UNIX 1
|
||||
#endif
|
||||
|
||||
// If these are already defined by someone else, assume they are also correct :P
|
||||
#if !(defined(IS_LITTLE_ENDIAN) || defined(IS_BIG_ENDIAN))
|
||||
|
||||
// CPU
|
||||
// .. IA-32
|
||||
#if defined(__i386__) || defined(__i386) || defined(_M_IX86)
|
||||
# define CPU_IA32 1
|
||||
#else
|
||||
# define CPU_IA32 0
|
||||
#endif
|
||||
// .. IA-64
|
||||
#if defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
|
||||
# define CPU_IA64 1
|
||||
#else
|
||||
# define CPU_IA64 0
|
||||
#endif
|
||||
// .. AMD64
|
||||
#if defined(__amd64__) || defined(__amd64) || defined(_M_AMD64)
|
||||
# define CPU_AMD64 1
|
||||
#else
|
||||
# define CPU_AMD64 0
|
||||
#endif
|
||||
// .. Alpha
|
||||
#if defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
|
||||
# define CPU_ALPHA 1
|
||||
#else
|
||||
# define CPU_ALPHA 0
|
||||
#endif
|
||||
// .. ARM
|
||||
#if defined(__arm__)
|
||||
# define CPU_ARM 1
|
||||
#else
|
||||
# define CPU_ARM 0
|
||||
#endif
|
||||
// .. MIPS
|
||||
#if defined(__MIPSEL__)
|
||||
# define CPU_MIPS 1
|
||||
#else
|
||||
# define CPU_MIPS 0
|
||||
#endif
|
||||
|
||||
|
||||
// byte order
|
||||
# if defined(__i386__) || defined(__i386) || defined(_M_IX86) || \
|
||||
defined(__ia64__) || defined(__ia64) || defined(_M_IA64) || \
|
||||
defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) || \
|
||||
defined(__arm__) || \
|
||||
defined(__MIPSEL__) || \
|
||||
defined(__LITTLE_ENDIAN__)
|
||||
# define IS_LITTLE_ENDIAN
|
||||
// if already defined by someone else, assume they are also correct :P
|
||||
#ifndef BYTE_ORDER
|
||||
# define LITTLE_ENDIAN 0x4321
|
||||
# define BIG_ENDIAN 0x1234
|
||||
# if CPU_IA32 || CPU_IA64 || CPU_AMD64 || CPU_ALPHA || CPU_ARM || CPU_MIPS || defined(__LITTLE_ENDIAN__)
|
||||
# define BYTE_ORDER LITTLE_ENDIAN
|
||||
# else
|
||||
# define IS_BIG_ENDIAN
|
||||
# define BYTE_ORDER BIG_ENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// auto-detect platform features, given the above information
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// compiler support for C99
|
||||
// (this is more convenient than testing __STDC_VERSION__ directly)
|
||||
#undef HAVE_C99
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||
# define HAVE_C99
|
||||
# define HAVE_C99 1
|
||||
#else
|
||||
# define HAVE_C99 0
|
||||
#endif
|
||||
|
||||
// gettimeofday()
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
#ifdef OS_UNIX
|
||||
# define HAVE_GETTIMEOFDAY
|
||||
#if OS_UNIX
|
||||
# define HAVE_GETTIMEOFDAY 1
|
||||
#else
|
||||
# define HAVE_GETTIMEOFDAY 0
|
||||
#endif
|
||||
|
||||
// clock_gettime()
|
||||
#if OS_LINUX
|
||||
# define HAVE_CLOCK_GETTIME 1
|
||||
#else
|
||||
# define HAVE_CLOCK_GETTIME 0
|
||||
#endif
|
||||
|
||||
// X server
|
||||
#undef HAVE_X
|
||||
#ifdef OS_LINUX
|
||||
# define HAVE_X
|
||||
#if OS_LINUX
|
||||
# define HAVE_X 1
|
||||
#else
|
||||
# define HAVE_X 0
|
||||
#endif
|
||||
|
||||
// __asm{} blocks (Intel syntax)
|
||||
#undef HAVE_ASM
|
||||
#if MSC_VERSION != 0
|
||||
# define HAVE_ASM
|
||||
#if MSC_VERSION
|
||||
# define HAVE_ASM 1
|
||||
#else
|
||||
# define HAVE_ASM 0
|
||||
#endif
|
||||
|
||||
// precompiled headers (affects what precompiled.h pulls in; see there)
|
||||
#undef HAVE_PCH
|
||||
#if (MSC_VERSION != 0) || (GCC_VERSION > 304)
|
||||
# define HAVE_PCH
|
||||
#if MSC_VERSION || (GCC_VERSION > 304)
|
||||
# define HAVE_PCH 1
|
||||
#else
|
||||
# define HAVE_PCH 0
|
||||
#endif
|
||||
|
||||
// VC debug memory allocator / leak detector
|
||||
#undef HAVE_VC_DEBUG_ALLOC
|
||||
#if MSC_VERSION != 0
|
||||
# define HAVE_VC_DEBUG_ALLOC
|
||||
#endif
|
||||
// .. only in full-debug mode;
|
||||
#if defined(NDEBUG) || defined(TESTING)
|
||||
# undef HAVE_VC_DEBUG_ALLOC
|
||||
#endif
|
||||
// .. require PCH, because it makes sure system headers are included before
|
||||
// redefining new (otherwise, tons of errors result);
|
||||
#if !defined(HAVE_PCH)
|
||||
# undef HAVE_VC_DEBUG_ALLOC
|
||||
#endif
|
||||
// .. disable on ICC9, because the ICC 9.0.006 beta appears to generate
|
||||
// incorrect code when we redefine new.
|
||||
// TODO: remove when no longer necessary
|
||||
#if ICC_VERSION == 900
|
||||
# undef HAVE_VC_DEBUG_ALLOC
|
||||
// notes:
|
||||
// - PCH is required because it makes sure system headers are included
|
||||
// before redefining new (otherwise, tons of errors result);
|
||||
// - disabled on ICC9 because the ICC 9.0.006 beta appears to generate
|
||||
// incorrect code when we redefine new.
|
||||
// TODO: remove when no longer necessary
|
||||
#if MSC_VERSION && \
|
||||
(!defined(NDEBUG) || defined(TESTING)) && \
|
||||
HAVE_PCH && \
|
||||
ICC_VERSION != 900
|
||||
# define HAVE_VC_DEBUG_ALLOC 1
|
||||
#else
|
||||
# define HAVE_VC_DEBUG_ALLOC 0
|
||||
#endif
|
||||
|
||||
// nonstandard STL containers
|
||||
#undef HAVE_STL_HASH
|
||||
#undef HAVE_STL_SLIST
|
||||
#define HAVE_STL_SLIST 0
|
||||
#if STL_DINKUMWARE != 0
|
||||
# define HAVE_STL_HASH
|
||||
# define HAVE_STL_HASH 1
|
||||
#else
|
||||
# define HAVE_STL_HASH 0
|
||||
#endif
|
||||
|
||||
#endif // #ifndef CONFIG_H_INCLUDED
|
||||
|
@ -23,11 +23,11 @@
|
||||
#include "lib.h"
|
||||
#include "debug.h"
|
||||
#include "debug_stl.h"
|
||||
#include "posix.h"
|
||||
#include "nommgr.h"
|
||||
// some functions here are called from within mmgr; disable its hooks
|
||||
// so that our allocations don't cause infinite recursion.
|
||||
|
||||
|
||||
// needed when writing crashlog
|
||||
static const size_t LOG_CHARS = 16384;
|
||||
wchar_t debug_log[LOG_CHARS];
|
||||
@ -336,7 +336,7 @@ const char* debug_get_symbol_string(void* symbol, const char* name, const char*
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ErrorReaction display_error(const wchar_t* description, int flags,
|
||||
uint skip, void* context, const char* file, int line)
|
||||
@ -408,7 +408,7 @@ ErrorReaction display_error(const wchar_t* description, int flags,
|
||||
// disable memory-leak reporting to avoid a flood of warnings
|
||||
// (lots of stuff will leak since we exit abnormally).
|
||||
debug_heap_enable(DEBUG_HEAP_NONE);
|
||||
#ifdef CONFIG_USE_MMGR
|
||||
#if CONFIG_USE_MMGR
|
||||
mmgr_set_options(0);
|
||||
#endif
|
||||
|
||||
@ -432,4 +432,76 @@ ErrorReaction debug_assert_failed(const char* file, int line, const char* expr)
|
||||
wchar_t buf[200];
|
||||
swprintf(buf, ARRAY_SIZE(buf), L"Assertion failed in %hs, line %d: \"%hs\"", base_name, line, expr);
|
||||
return display_error(buf, DE_ALLOW_SUPPRESS|DE_MANUAL_BREAK, skip, context, base_name, line);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// thread naming
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// when debugging multithreading problems, logging the currently running
|
||||
// thread is helpful; a user-specified name is easier to remember than just
|
||||
// the thread handle. to that end, we provide a robust TLS mechanism that is
|
||||
// much safer than the previous method of hijacking TIB.pvArbitrary.
|
||||
//
|
||||
// note: on Win9x thread "IDs" are pointers to the TIB xor-ed with an
|
||||
// obfuscation value calculated at boot-time.
|
||||
//
|
||||
// __declspec(thread) et al. are now available on VC and newer GCC but we
|
||||
// implement TLS manually (via pthread_setspecific) to ensure compatibility.
|
||||
|
||||
static pthread_key_t tls_key;
|
||||
static pthread_once_t tls_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
|
||||
// provided for completeness and to avoid displaying bogus resource leaks.
|
||||
static void tls_shutdown()
|
||||
{
|
||||
WARN_ERR(pthread_key_delete(tls_key));
|
||||
tls_key = 0;
|
||||
}
|
||||
|
||||
|
||||
// (called via pthread_once from debug_set_thread_name)
|
||||
static void tls_init()
|
||||
{
|
||||
WARN_ERR(pthread_key_create(&tls_key, 0)); // no dtor
|
||||
|
||||
// note: do not use atexit; this may be called before _cinit.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// set the current thread's name; it will be returned by subsequent calls to
|
||||
// debug_get_thread_name.
|
||||
//
|
||||
// the string pointed to by <name> MUST remain valid throughout the
|
||||
// entire program; best to pass a string literal. allocating a copy
|
||||
// would be quite a bit more work due to cleanup issues.
|
||||
//
|
||||
// if supported on this platform, the debugger is notified of the new name;
|
||||
// it will be displayed there instead of just the handle.
|
||||
void debug_set_thread_name(const char* name)
|
||||
{
|
||||
WARN_ERR(pthread_once(&tls_once, tls_init));
|
||||
|
||||
WARN_ERR(pthread_setspecific(tls_key, name));
|
||||
|
||||
wdbg_set_thread_name(name);
|
||||
}
|
||||
|
||||
|
||||
// return the pointer assigned by debug_set_thread_name or 0 if
|
||||
// that hasn't been done yet for this thread.
|
||||
const char* debug_get_thread_name()
|
||||
{
|
||||
return (const char*)pthread_getspecific(tls_key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void debug_shutdown()
|
||||
{
|
||||
tls_shutdown();
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "lib.h" // STMT
|
||||
#include "sysdep/sysdep.h" // ErrorReaction
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
# include "sysdep/win/wdbg.h"
|
||||
#else
|
||||
# include "sysdep/unix/udbg.h"
|
||||
@ -107,7 +107,7 @@ extern void debug_heap_enable(DebugHeapChecks what);
|
||||
// the string can pass more information about the problem on to whomever
|
||||
// is seeing the error.
|
||||
//
|
||||
// rationale: 0x55 and 0xaa have distinctive bit patterns and thus
|
||||
// rationale: 0x55 and 0xAA are distinctive values and thus
|
||||
// help debug the symbol engine.
|
||||
#define debug_assert(expr) \
|
||||
STMT(\
|
||||
@ -117,7 +117,7 @@ STMT(\
|
||||
switch(debug_assert_failed(__FILE__, __LINE__, #expr))\
|
||||
{\
|
||||
case ER_SUPPRESS:\
|
||||
suppress__ = 0xaa;\
|
||||
suppress__ = 0xAA;\
|
||||
break;\
|
||||
case ER_BREAK:\
|
||||
debug_break();\
|
||||
@ -142,8 +142,12 @@ extern enum ErrorReaction debug_assert_failed(const char* source_file, int line,
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// show a dialog to make sure unexpected states in the program are noticed.
|
||||
// this is less error-prone than debug_assert(!"text");
|
||||
#define debug_warn(str) debug_assert(0 && (str))
|
||||
// this is less error-prone than "debug_assert(0 && "text");" and avoids
|
||||
// "conditional expression is constant" warnings. we'd really like to
|
||||
// completely eliminate the problem; replacing 0 literals with extern
|
||||
// volatile variables fools VC7 but isn't guaranteed to be free of overhead.
|
||||
// we therefore just squelch the warning (unfortunately non-portable).
|
||||
#define debug_warn(str) debug_assert((str) && 0)
|
||||
|
||||
// write to the debugger output window (may take ~1 ms!)
|
||||
extern void debug_printf(const char* fmt, ...);
|
||||
@ -247,9 +251,28 @@ typedef const u8* (*DebugIterator)(void* internal, size_t el_size);
|
||||
extern void* debug_get_nth_caller(uint skip, void* context);
|
||||
|
||||
// return 1 if the pointer appears to be totally bogus, otherwise 0.
|
||||
// this check is not authoritative in that the pointer may in truth
|
||||
// be invalid regardless of the return value here, but can be used
|
||||
// to filter out obviously wrong values in a portable manner.
|
||||
extern int debug_is_bogus_pointer(const void* p);
|
||||
// this check is not authoritative (the pointer may be "valid" but incorrect)
|
||||
// but can be used to filter out obviously wrong values in a portable manner.
|
||||
extern int debug_is_pointer_bogus(const void* p);
|
||||
|
||||
|
||||
// set the current thread's name; it will be returned by subsequent calls to
|
||||
// debug_get_thread_name.
|
||||
//
|
||||
// the string pointed to by <name> MUST remain valid throughout the
|
||||
// entire program; best to pass a string literal. allocating a copy
|
||||
// would be quite a bit more work due to cleanup issues.
|
||||
//
|
||||
// if supported on this platform, the debugger is notified of the new name;
|
||||
// it will be displayed there instead of just the handle.
|
||||
extern void debug_set_thread_name(const char* name);
|
||||
|
||||
// return the pointer assigned by debug_set_thread_name or 0 if
|
||||
// that hasn't been done yet for this thread.
|
||||
extern const char* debug_get_thread_name();
|
||||
|
||||
|
||||
// call at exit to avoid leaks (not strictly necessary).
|
||||
extern void debug_shutdown();
|
||||
|
||||
#endif // #ifndef DEBUG_H_INCLUDED
|
||||
|
@ -68,7 +68,7 @@ char* stl_simplify_name(char* name)
|
||||
// for each character: (except those skipped as parts of strings)
|
||||
for(;;)
|
||||
{
|
||||
int c = *(++src);
|
||||
char c = *(++src);
|
||||
// preincrement rationale: src++ with no further changes would
|
||||
// require all comparisons to subtract 1. incrementing at the
|
||||
// end of a loop would require a goto, instead of continue
|
||||
@ -184,7 +184,7 @@ static bool container_valid(const void* front, size_t el_count)
|
||||
if(el_count > 0x1000000)
|
||||
return false;
|
||||
|
||||
if(debug_is_bogus_pointer(front))
|
||||
if(debug_is_pointer_bogus(front))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -212,9 +212,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t el_size) const
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
UNUSED(el_size);
|
||||
return size();
|
||||
}
|
||||
|
||||
@ -231,7 +230,7 @@ public:
|
||||
};
|
||||
*/
|
||||
|
||||
#ifndef OS_UNIX
|
||||
#if !OS_UNIX
|
||||
|
||||
//
|
||||
// standard containers
|
||||
@ -270,9 +269,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t el_size) const
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
UNUSED(el_size);
|
||||
return size();
|
||||
}
|
||||
|
||||
@ -295,23 +293,22 @@ public:
|
||||
class Any_list : public std::list<int>
|
||||
{
|
||||
public:
|
||||
bool valid(size_t el_size) const
|
||||
bool valid(size_t UNUSED(el_size)) const
|
||||
{
|
||||
if(!container_valid(_Myhead, _Mysize))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t el_size) const
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
UNUSED(el_size);
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter : public const_iterator
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t el_size)
|
||||
const u8* deref_and_advance(size_t UNUSED(el_size))
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
++(*this);
|
||||
@ -336,16 +333,17 @@ template<class _Traits> class Any_tree : public std::_Tree<_Traits>
|
||||
}
|
||||
|
||||
public:
|
||||
bool valid(size_t el_size) const
|
||||
Any_tree() {}
|
||||
|
||||
bool valid(size_t UNUSED(el_size)) const
|
||||
{
|
||||
if(!container_valid(_Myhead, _Mysize))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t el_size) const
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
UNUSED(el_size);
|
||||
return size();
|
||||
}
|
||||
|
||||
@ -407,7 +405,7 @@ class Any_multiset: public Any_set
|
||||
class Any_vector: public std::vector<int>
|
||||
{
|
||||
public:
|
||||
bool valid(size_t el_size) const
|
||||
bool valid(size_t UNUSED(el_size)) const
|
||||
{
|
||||
if(!container_valid(_Myfirst, _Mylast-_Myfirst))
|
||||
return false;
|
||||
@ -465,16 +463,15 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t el_size) const
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
UNUSED(el_size);
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter : public const_iterator
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t el_size)
|
||||
const u8* deref_and_advance(size_t UNUSED(el_size))
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
++(*this);
|
||||
@ -506,7 +503,7 @@ class Any_stack : public Any_deque
|
||||
// nonstandard containers (will probably be part of C++0x)
|
||||
//
|
||||
|
||||
#ifdef HAVE_STL_HASH
|
||||
#if HAVE_STL_HASH
|
||||
|
||||
|
||||
class Any_hash_map: public STL_HASH_MAP<int,int>
|
||||
@ -520,16 +517,15 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t el_size) const
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
UNUSED(el_size);
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter : public const_iterator
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t el_size)
|
||||
const u8* deref_and_advance(size_t UNUSED(el_size))
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
++(*this);
|
||||
@ -555,16 +551,15 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t el_count(size_t el_size) const
|
||||
size_t el_count(size_t UNUSED(el_size)) const
|
||||
{
|
||||
UNUSED(el_size);
|
||||
return size();
|
||||
}
|
||||
|
||||
class iter : public const_iterator
|
||||
{
|
||||
public:
|
||||
const u8* deref_and_advance(size_t el_size)
|
||||
const u8* deref_and_advance(size_t UNUSED(el_size))
|
||||
{
|
||||
const u8* p = (const u8*)&operator*();
|
||||
++(*this);
|
||||
@ -580,7 +575,7 @@ class Any_hash_multiset : public Any_hash_set
|
||||
|
||||
#endif // HAVE_STL_HASH
|
||||
|
||||
#ifdef HAVE_STL_SLIST
|
||||
#if HAVE_STL_SLIST
|
||||
|
||||
|
||||
class Any_slist: public Any_list
|
||||
@ -633,7 +628,7 @@ int stl_get_container_info(const char* type_name, const u8* p, size_t size,
|
||||
// HACK: The debug_stl code breaks VS2005's STL badly, causing crashes in
|
||||
// later pieces of code that try to manipulate the STL containers. Presumably
|
||||
// it needs to be altered/rewritten to work happily with the new STL debug iterators.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
#if MSC_VERSION >= 1400
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
@ -670,13 +665,13 @@ int stl_get_container_info(const char* type_name, const u8* p, size_t size,
|
||||
CONTAINER(queue, "std::queue<*,std::deque<*> >")
|
||||
CONTAINER(stack, "std::stack<*,std::deque<*> >")
|
||||
// nonstandard containers (will probably be part of C++0x)
|
||||
#ifdef HAVE_STL_HASH
|
||||
#if HAVE_STL_HASH
|
||||
CONTAINER(hash_map, STRINGIZE(STL_HASH_MAP) "<*>")
|
||||
CONTAINER(hash_multimap, STRINGIZE(STL_HASH_MULTIMAP) "<*>")
|
||||
CONTAINER(hash_set, STRINGIZE(STL_HASH_SET) "<*>")
|
||||
CONTAINER(hash_multiset, STRINGIZE(STL_HASH_MULTISET) "<*>")
|
||||
#endif
|
||||
#ifdef HAVE_STL_SLIST
|
||||
#if HAVE_STL_SLIST
|
||||
CONTAINER(slist, STRINGIZE(STL_SLIST) "<*>")
|
||||
#endif
|
||||
|
||||
@ -686,4 +681,5 @@ int stl_get_container_info(const char* type_name, const u8* p, size_t size,
|
||||
return STL_CNT_INVALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -28,11 +28,11 @@
|
||||
#include "timer.h"
|
||||
#include "sdl.h"
|
||||
|
||||
#ifdef _M_IX86
|
||||
#if CPU_IA32
|
||||
extern void ia32_get_cpu_info();
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
extern int win_get_gfx_info();
|
||||
extern int win_get_cpu_info();
|
||||
extern int win_get_snd_info();
|
||||
@ -58,13 +58,13 @@ void get_mem_status()
|
||||
#endif
|
||||
|
||||
// Sys V derived (GNU/Linux, Solaris)
|
||||
#ifdef _SC_AVPHYS_PAGES
|
||||
#if defined(_SC_AVPHYS_PAGES)
|
||||
|
||||
tot_mem = sysconf(_SC_PHYS_PAGES ) * page_size;
|
||||
avl_mem = sysconf(_SC_AVPHYS_PAGES) * page_size;
|
||||
|
||||
// BSD / Mac OS X
|
||||
#elif HAVE_SYSCTL && defined(HW_PHYSMEM)
|
||||
#elif defined(HW_PHYSMEM)
|
||||
|
||||
size_t len = sizeof(tot_mem);
|
||||
int mib[2] = { CTL_HW, HW_PHYSMEM };
|
||||
@ -99,7 +99,7 @@ void get_gfx_info()
|
||||
// try platform-specific versions first: they return more
|
||||
// detailed information, and don't require OpenGL to be ready.
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
ret = win_get_gfx_info();
|
||||
#endif
|
||||
|
||||
@ -129,11 +129,11 @@ int cpu_smp = -1;
|
||||
|
||||
void get_cpu_info()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
win_get_cpu_info();
|
||||
#endif
|
||||
|
||||
#ifdef _M_IX86
|
||||
#if CPU_IA32
|
||||
ia32_get_cpu_info();
|
||||
#endif
|
||||
}
|
||||
@ -148,7 +148,7 @@ char snd_drv_ver[SND_DRV_VER_LEN];
|
||||
|
||||
void get_snd_info()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
win_get_snd_info();
|
||||
#else
|
||||
// At least reset the values for unhandled platforms. Should perhaps do
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <GL/glext.h>
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
# include <GL/wglext.h>
|
||||
#endif
|
||||
/*
|
||||
@ -66,7 +66,7 @@ FUNC2(void, glCompressedTexSubImage2DARB, glCompressedTexSubImage2D, "1.3", (GLe
|
||||
FUNC2(void, glCompressedTexSubImage1DARB, glCompressedTexSubImage1D, "1.3", (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*))
|
||||
FUNC2(void, glGetCompressedTexImageARB, glGetCompressedTexImage, "1.3", (GLenum, GLint, GLvoid*))
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
// WGL_EXT_swap_control
|
||||
FUNC(int, wglSwapIntervalEXT, (int))
|
||||
|
||||
@ -81,4 +81,4 @@ FUNC(int, wglQueryPbufferARB, (HPBUFFERARB, int, int*))
|
||||
FUNC(int, wglGetPixelFormatAttribivARB, (HDC, int, int, unsigned int, const int*, int*))
|
||||
FUNC(int, wglGetPixelFormatAttribfvARB, (HDC, int, int, unsigned int, const int*, float*))
|
||||
FUNC(int, wglChoosePixelFormatARB, (HDC, const int *, const float*, unsigned int, int*, unsigned int*))
|
||||
#endif // _WIN32
|
||||
#endif // OS_WIN
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#if 0
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits.h>
|
||||
|
||||
@ -580,3 +582,4 @@ bucket = prev_bucket;
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
@ -146,7 +146,7 @@ bool is_pow2(const long n)
|
||||
|
||||
int ilog2(const int n)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
#if CPU_IA32
|
||||
|
||||
__asm
|
||||
{
|
||||
@ -266,6 +266,20 @@ i64 movsx_64le(const u8* p, size_t size)
|
||||
}
|
||||
|
||||
|
||||
// these avoid a common mistake in using >> (ANSI requires shift count be
|
||||
// less than the bit width of the type).
|
||||
|
||||
u32 u64_hi(u64 x)
|
||||
{
|
||||
return (u32)(x >> 32);
|
||||
}
|
||||
|
||||
u32 u64_lo(u64 x)
|
||||
{
|
||||
return (u32)(x & 0xffffffff);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// input in [0, 1); convert to u8 range
|
||||
u8 fp_to_u8(double in)
|
||||
|
@ -67,21 +67,15 @@ scope
|
||||
#define EXTERN_C extern
|
||||
#endif
|
||||
|
||||
|
||||
// tell STL not to generate exceptions, if compiling without exceptions
|
||||
// (usually done for performance reasons).
|
||||
#ifdef CONFIG_DISABLE_EXCEPTIONS
|
||||
# ifdef _WIN32
|
||||
# define _HAS_EXCEPTIONS 0
|
||||
# else
|
||||
# define STL_NO_EXCEPTIONS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#define STMT(STMT_code__) do { STMT_code__; } while(0)
|
||||
// package code into a single statement.
|
||||
// notes:
|
||||
// - for(;;) { break; } and {} don't work because invocations of macros
|
||||
// implemented with STMT often end with ";", thus breaking if() expressions.
|
||||
// - we'd really like to eliminate "conditional expression is constant"
|
||||
// warnings. replacing 0 literals with extern volatile variables fools
|
||||
// VC7 but isn't guaranteed to be free of overhead. we will just
|
||||
// squelch the warning (unfortunately non-portable).
|
||||
#define STMT(STMT_code__) do { STMT_code__; } while(false)
|
||||
|
||||
// may be called at any time (in particular before main), but is not
|
||||
// thread-safe. if that's important, use pthread_once() instead.
|
||||
@ -105,7 +99,8 @@ STMT(\
|
||||
// therefore known to fit; we still mask with UINT_MAX to avoid
|
||||
// VC cast-to-smaller-type warnings.
|
||||
|
||||
#ifdef _WIN32
|
||||
// if expression evaluates to a negative i64, warn user and return the number.
|
||||
#if OS_WIN
|
||||
#define CHECK_ERR(expression)\
|
||||
STMT(\
|
||||
i64 err__ = (i64)(expression);\
|
||||
@ -138,17 +133,40 @@ STMT(\
|
||||
return (int)(err__ & UINT_MAX);\
|
||||
)
|
||||
|
||||
// if expression evaluates to a negative i64, warn user and throw the number.
|
||||
#define THROW_ERR(expression)\
|
||||
STMT(\
|
||||
i64 err__ = (i64)(expression);\
|
||||
if(err__ < 0)\
|
||||
{\
|
||||
debug_warn("FYI: CHECK_ERR reports that a function failed."\
|
||||
debug_warn("FYI: THROW_ERR reports that a function failed."\
|
||||
"feel free to ignore or suppress this warning.");\
|
||||
throw (int)(err__ & UINT_MAX);\
|
||||
}\
|
||||
)
|
||||
|
||||
// if expression evaluates to a negative i64, warn user and just return
|
||||
// (useful for void functions that must bail and complain)
|
||||
#define WARN_ERR_RETURN(expression)\
|
||||
STMT(\
|
||||
i64 err__ = (i64)(expression);\
|
||||
if(err__ < 0)\
|
||||
{\
|
||||
debug_warn("FYI: WARN_ERR_RETURN reports that a function failed."\
|
||||
"feel free to ignore or suppress this warning.");\
|
||||
return;\
|
||||
}\
|
||||
)
|
||||
|
||||
// if expression evaluates to a negative i64, warn user
|
||||
// (this is similar to debug_assert but also works in release mode)
|
||||
#define WARN_ERR(expression)\
|
||||
STMT(\
|
||||
i64 err__ = (i64)(expression);\
|
||||
if(err__ < 0)\
|
||||
debug_warn("FYI: WARN_ERR reports that a function failed."\
|
||||
"feel free to ignore or suppress this warning.");\
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -188,7 +206,7 @@ enum LibError
|
||||
// .. feature won't be supported
|
||||
ERR_NOT_SUPPORTED = -1025,
|
||||
|
||||
// file contents are damaged
|
||||
// data (e.g. in file) is obviously incorrect
|
||||
ERR_CORRUPTED = -1040,
|
||||
|
||||
ERR_UNKNOWN_FORMAT = -1050,
|
||||
@ -198,12 +216,13 @@ enum LibError
|
||||
// file + vfs
|
||||
ERR_FILE_NOT_FOUND = -1200,
|
||||
ERR_PATH_NOT_FOUND = -1201,
|
||||
ERR_DIR_END = -1202,
|
||||
ERR_EOF = -1203,
|
||||
ERR_PATH_LENGTH = -1204,
|
||||
ERR_NOT_FILE = -1205,
|
||||
ERR_FILE_ACCESS = -1206,
|
||||
ERR_IO = -1207,
|
||||
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,
|
||||
|
||||
|
||||
ERR_TEX_FMT_INVALID = -1300,
|
||||
@ -225,10 +244,14 @@ enum LibError
|
||||
|
||||
|
||||
// 2 ways of avoiding "unreferenced formal parameter" warnings:
|
||||
// .. inside the function body, e.g. void f(int x) { UNUSED(x); }
|
||||
#define UNUSED(param) (void)param;
|
||||
// .. wrapped around the parameter name, e.g. void f(int UNUSEDPARAM(x))
|
||||
#define UNUSEDPARAM(param)
|
||||
// .. inside the function body, e.g. void f(int x) { UNUSED2(x); }
|
||||
#define UNUSED2(param) (void)param;
|
||||
// .. wrapped around the parameter name, e.g. void f(int UNUSED(x))
|
||||
#define UNUSED(param)
|
||||
|
||||
#if MSC_VERSION
|
||||
#define UNREACHABLE __assume(0)
|
||||
#endif
|
||||
|
||||
|
||||
#define ARRAY_SIZE(name) (sizeof(name) / sizeof(name[0]))
|
||||
@ -270,7 +293,7 @@ const size_t MiB = 1ul << 20;
|
||||
const size_t GiB = 1ul << 30;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
#define DIR_SEP '\\'
|
||||
#else
|
||||
#define DIR_SEP '/'
|
||||
@ -322,6 +345,12 @@ extern uint log2(uint x);
|
||||
// multiple must be a power of two.
|
||||
extern uintptr_t round_up(uintptr_t val, uintptr_t multiple);
|
||||
|
||||
// these avoid a common mistake in using >> (ANSI requires shift count be
|
||||
// less than the bit width of the type).
|
||||
extern u32 u64_hi(u64 x);
|
||||
extern u32 u64_lo(u64 x);
|
||||
|
||||
|
||||
extern u16 fp_to_u16(double in);
|
||||
|
||||
// return random integer in [0, limit).
|
||||
|
@ -149,16 +149,14 @@ static void tls_retire(void* tls_)
|
||||
// (called via pthread_once from tls_get)
|
||||
static void tls_init()
|
||||
{
|
||||
int ret = pthread_key_create(&tls_key, tls_retire);
|
||||
debug_assert(ret == 0);
|
||||
WARN_ERR(pthread_key_create(&tls_key, tls_retire));
|
||||
}
|
||||
|
||||
|
||||
// free all TLS info. called by smr_try_shutdown.
|
||||
static void tls_shutdown()
|
||||
{
|
||||
int ret = pthread_key_delete(tls_key);
|
||||
debug_assert(ret == 0);
|
||||
WARN_ERR(pthread_key_delete(tls_key));
|
||||
tls_key = 0;
|
||||
|
||||
while(tls_list)
|
||||
@ -197,8 +195,7 @@ static TLS* tls_alloc()
|
||||
if(!tls)
|
||||
{
|
||||
tls = (TLS*)-1;
|
||||
int ret = pthread_setspecific(tls_key, tls);
|
||||
debug_assert(ret == 0);
|
||||
WARN_ERR(pthread_setspecific(tls_key, tls));
|
||||
return tls;
|
||||
}
|
||||
tls->active = 1;
|
||||
@ -216,8 +213,7 @@ static TLS* tls_alloc()
|
||||
have_tls:
|
||||
atomic_add(&active_threads, 1);
|
||||
|
||||
int ret = pthread_setspecific(tls_key, tls);
|
||||
debug_assert(ret == 0);
|
||||
WARN_ERR(pthread_setspecific(tls_key, tls));
|
||||
return tls;
|
||||
}
|
||||
|
||||
@ -226,8 +222,7 @@ have_tls:
|
||||
// called from each lfl_* function, so don't waste any time.
|
||||
static TLS* tls_get()
|
||||
{
|
||||
int ret = pthread_once(&tls_once, tls_init);
|
||||
debug_assert(ret == 0);
|
||||
WARN_ERR(pthread_once(&tls_once, tls_init));
|
||||
|
||||
// already allocated or tls_alloc failed.
|
||||
TLS* tls = (TLS*)pthread_getspecific(tls_key);
|
||||
@ -678,7 +673,7 @@ static LFList* chain(LFHash* hash, uintptr_t key)
|
||||
int lfh_init(LFHash* hash, size_t num_entries)
|
||||
{
|
||||
hash->tbl = 0;
|
||||
hash->mask = ~0;
|
||||
hash->mask = ~0u;
|
||||
|
||||
if(!is_pow2((long)num_entries))
|
||||
{
|
||||
@ -767,12 +762,10 @@ static void basic_single_threaded_test()
|
||||
int sig = 10;
|
||||
|
||||
LFList list;
|
||||
err = lfl_init(&list);
|
||||
debug_assert(err == 0);
|
||||
WARN_ERR(lfl_init(&list));
|
||||
|
||||
LFHash hash;
|
||||
err = lfh_init(&hash, 8);
|
||||
debug_assert(err == 0);
|
||||
WARN_ERR(lfh_init(&hash, 8));
|
||||
|
||||
// add some entries; store "signatures" (ascending int values)
|
||||
for(uint i = 0; i < ENTRIES; i++)
|
||||
@ -825,6 +818,8 @@ static pthread_mutex_t mutex; // protects <keys>
|
||||
|
||||
static void* thread_func(void* arg)
|
||||
{
|
||||
debug_set_thread_name("LF_test");
|
||||
|
||||
const uintptr_t thread_number = (uintptr_t)arg;
|
||||
|
||||
atomic_add(&num_active_threads, 1);
|
||||
@ -933,12 +928,9 @@ static void multithreaded_torture_test()
|
||||
const double end_time = get_time() + TEST_LENGTH;
|
||||
is_complete = false;
|
||||
|
||||
err = lfl_init(&list);
|
||||
debug_assert(err == 0);
|
||||
err = lfh_init(&hash, 128);
|
||||
debug_assert(err == 0);
|
||||
err = pthread_mutex_init(&mutex, 0);
|
||||
debug_assert(err == 0);
|
||||
WARN_ERR(lfl_init(&list));
|
||||
WARN_ERR(lfh_init(&hash, 128));
|
||||
WARN_ERR(pthread_mutex_init(&mutex, 0));
|
||||
|
||||
// spin off test threads (many, to force preemption)
|
||||
const uint NUM_THREADS = 16;
|
||||
@ -957,8 +949,7 @@ static void multithreaded_torture_test()
|
||||
|
||||
lfl_free(&list);
|
||||
lfh_free(&hash);
|
||||
err = pthread_mutex_destroy(&mutex);
|
||||
debug_assert(err == 0);
|
||||
WARN_ERR(pthread_mutex_destroy(&mutex));
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,14 +98,6 @@ terminology
|
||||
*/
|
||||
|
||||
|
||||
// atomic "compare and swap". compare the machine word at <location> against
|
||||
// <expected>; if not equal, return false; otherwise, overwrite it with
|
||||
// <new_value> and return true.
|
||||
extern bool CAS_(uintptr_t* location, uintptr_t expected, uintptr_t new_value);
|
||||
|
||||
#define CAS(l,o,n) CAS_((uintptr_t*)l, (uintptr_t)o, (uintptr_t)n)
|
||||
|
||||
|
||||
//
|
||||
// lock-free singly linked list
|
||||
//
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "precompiled.h"
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_ASM
|
||||
#if HAVE_ASM
|
||||
|
||||
void memcpy_nt(void* dst, void* src, int len)
|
||||
{
|
||||
@ -65,4 +65,4 @@ write_loop:
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef HAVE_ASM
|
||||
#endif // #if HAVE_ASM
|
||||
|
@ -21,7 +21,7 @@
|
||||
// for easy removal in release builds, so that we don't cause any overhead.
|
||||
// note that any application calls to our functions must be removed also,
|
||||
// but this is preferable to stubbing them out here ("least surprise").
|
||||
#ifdef CONFIG_USE_MMGR
|
||||
#if CONFIG_USE_MMGR
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -35,7 +35,7 @@
|
||||
#include "mmgr.h"
|
||||
#include "lib.h"
|
||||
#include "posix.h"
|
||||
#include "sysdep/debug.h"
|
||||
#include "debug.h"
|
||||
|
||||
// remove macro hooks (we need to use the actual malloc/new etc. routines)
|
||||
#include "nommgr.h"
|
||||
@ -59,27 +59,20 @@ static void lock_init() throw()
|
||||
|
||||
static void lock_shutdown() throw()
|
||||
{
|
||||
int ret = pthread_mutex_destroy(&mutex);
|
||||
debug_assert(ret == 0);
|
||||
WARN_ERR(pthread_mutex_destroy(&mutex));
|
||||
lock_initialized = false;
|
||||
}
|
||||
|
||||
static void lock() throw()
|
||||
{
|
||||
if(lock_initialized)
|
||||
{
|
||||
int ret = pthread_mutex_lock(&mutex);
|
||||
debug_assert(ret == 0);
|
||||
}
|
||||
WARN_ERR(pthread_mutex_lock(&mutex));
|
||||
}
|
||||
|
||||
static void unlock() throw()
|
||||
{
|
||||
if(lock_initialized)
|
||||
{
|
||||
int ret = pthread_mutex_unlock(&mutex);
|
||||
debug_assert(ret == 0);
|
||||
}
|
||||
WARN_ERR(pthread_mutex_unlock(&mutex));
|
||||
}
|
||||
|
||||
|
||||
@ -97,7 +90,7 @@ static void unlock() throw()
|
||||
// user's buffer. pattern_set assumes it's an integral number of ulongs.
|
||||
|
||||
// enable all checks (slow!)
|
||||
#ifdef PARANOIA
|
||||
#if CONFIG_PARANOIA
|
||||
static uint options = MMGR_ALL;
|
||||
static const size_t padding_size = 256 * sizeof(ulong);
|
||||
// normal settings
|
||||
@ -1135,7 +1128,7 @@ fail:
|
||||
void* realloc_dbg(const void* user_p, size_t user_size, AllocType type, const char* file, int line, const char* func, uint stack_frames)
|
||||
{
|
||||
void* ret = 0;
|
||||
uint old_size = 0;
|
||||
size_t old_size = 0;
|
||||
|
||||
debug_assert(type == AT_REALLOC);
|
||||
|
||||
@ -1388,4 +1381,4 @@ void operator delete[](void* p, const char* file, int line, const char* func) th
|
||||
free_dbg(p, AT_DELETE_ARRAY, file,line,func, 1);
|
||||
}
|
||||
|
||||
#endif // #ifdef CONFIG_USE_MMGR
|
||||
#endif // #if CONFIG_USE_MMGR
|
||||
|
@ -16,19 +16,98 @@
|
||||
// Jan.Wassenberg@stud.uni-karlsruhe.de
|
||||
// http://www.stud.uni-karlsruhe.de/~urkt/
|
||||
|
||||
/*
|
||||
|
||||
// !!!!!!!!!! see user guide / documentation at end of file !!!!!!!!!!
|
||||
purpose and history
|
||||
-------------------
|
||||
|
||||
our goal is to expose any memory handling bugs in the application as
|
||||
early as possible. various checks are performed upon each memory API call;
|
||||
if all options are on, we can spot the following:
|
||||
memory leaks, double-free, allocation over/underruns,
|
||||
unused memory, and use-after-free.
|
||||
|
||||
this code started life as Paul Nettle's memory manager (available
|
||||
at http:www.fluidstudios.com), and has been completely overhauled.
|
||||
in particular, it is now thread-safe and modularized;
|
||||
duplicated code has been eliminated.
|
||||
|
||||
|
||||
instructions for integrating into your project
|
||||
----------------------------------------------
|
||||
|
||||
1) #include this from all project source files [that will allocate memory].
|
||||
doing so from the precompiled header is recommended, since the
|
||||
compiler will make sure it has actually been included.
|
||||
2) all system headers must be #include-d before this header, so that
|
||||
we don't mess with any of their local operator new/delete.
|
||||
3) if project source/headers also use local operator new/delete, #include
|
||||
"nommgr.h" before that spot, and re-#include "mmgr.h" afterwards.
|
||||
|
||||
4) if using MFC:
|
||||
- set linker option /FORCE - works around conflict between our global
|
||||
operator new and that of MFC. be sure to check for other errors.
|
||||
- remove any #define new DEBUG_NEW from all source files.
|
||||
|
||||
|
||||
effects
|
||||
-------
|
||||
|
||||
many bugs are caught and announced with no further changes
|
||||
required, due to integrity checks inside the allocator.
|
||||
|
||||
at exit, three report files are generated: a listing of leaks,
|
||||
various statistics (e.g. total unused memory), and the log.
|
||||
this lists (depending on settings) all allocations, enter/exit
|
||||
indications for our functions, and failure notifications.
|
||||
|
||||
|
||||
digging deeper
|
||||
--------------
|
||||
|
||||
when tracking down hard-to-find bugs, more stringent checks can be
|
||||
activated via mmgr_set_option, or by changing the initial value of
|
||||
options in mmgr.cpp. however, they slow down the app considerably
|
||||
and need not always be enabled. see option declarations above.
|
||||
|
||||
you can also change padding_size in mmgr.cpp at compile-time to provide
|
||||
more safety vs. overruns, at the cost of wasting lots of memory per
|
||||
allocation (which must also be cleared). this is only done in
|
||||
CONFIG_PARANOIA builds, because overruns seldom 'skip' padding.
|
||||
|
||||
finally, you can induce memory allocations to fail a certain percentage
|
||||
of the time - this tests your application's error handling.
|
||||
adjust the RANDOM_FAILURE #define in mmgr.cpp.
|
||||
|
||||
|
||||
fixing your bugs
|
||||
----------------
|
||||
|
||||
if this code crashes or fails an debug_assert, it is most likely due to a bug
|
||||
in your application. consult the current Alloc for information;
|
||||
search the log for its address to determine what operation failed,
|
||||
and what piece of code owns the allocation.
|
||||
|
||||
if the cause isn't visible (i.e. the error is reported after the fact),
|
||||
you can try activating the more stringent checks to catch the problem
|
||||
earlier. you may also call the validation routines at checkpoints
|
||||
in your code to narrow the cause down. if all else fails, break on
|
||||
the allocation number to see what's happening.
|
||||
|
||||
good luck!
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MMGR_H__
|
||||
#define MMGR_H__
|
||||
|
||||
// provide for completely disabling the memory manager
|
||||
// (e.g. when using other debug packages)
|
||||
//
|
||||
// note: checking here messes up include guard detection, but we need to
|
||||
// cover both the guarded part (constants+externs) and the macros.
|
||||
#ifdef CONFIG_USE_MMGR
|
||||
|
||||
#ifndef MMGR_H__
|
||||
#define MMGR_H__
|
||||
// note: this must go around the include-guarded part (constants+externs)
|
||||
// as well as the macros. we don't want to mess up compiler include-guard
|
||||
// optimizations, so duplicate this #if.
|
||||
#if CONFIG_USE_MMGR
|
||||
|
||||
#include "lib/types.h"
|
||||
|
||||
@ -125,6 +204,7 @@ extern void operator delete[](void* p, const char* file, int line) throw();
|
||||
extern void operator delete (void* p, const char* file, int line, const char* func) throw();
|
||||
extern void operator delete[](void* p, const char* file, int line, const char* func) throw();
|
||||
|
||||
#endif // #if CONFIG_USE_MMGR
|
||||
|
||||
#endif // #ifdef MMGR_H__
|
||||
|
||||
@ -135,9 +215,14 @@ extern void operator delete[](void* p, const char* file, int line, const char* f
|
||||
|
||||
#include "nommgr.h"
|
||||
|
||||
// MMGR version:
|
||||
// (to simplify code that may either use mmgr or the VC debug heap,
|
||||
// we support enabling/disabling both in this header)
|
||||
#if CONFIG_USE_MMGR
|
||||
|
||||
// get rid of __FUNCTION__ unless we know the compiler supports it.
|
||||
// (note: don't define if built-in - compiler will raise a warning)
|
||||
#if !defined(_MSC_VER) && !defined(__GNUC__)
|
||||
#if !MSC_VERSION && !GCC_VERSION
|
||||
#define __FUNCTION__ 0
|
||||
#endif
|
||||
|
||||
@ -154,83 +239,12 @@ extern void operator delete[](void* p, const char* file, int line, const char* f
|
||||
#define wcsdup(p) mmgr_wcsdup_dbg(p, __FILE__,__LINE__,__FUNCTION__)
|
||||
#define getcwd(p,size) mmgr_getcwd_dbg(p, size, __FILE__,__LINE__,__FUNCTION__)
|
||||
|
||||
#endif // #ifdef CONFIG_USE_MMGR
|
||||
#elif HAVE_VC_DEBUG_ALLOC
|
||||
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <crtdbg.h>
|
||||
// crtdbg.h didn't define "new" (probably for compatibility); do so now.
|
||||
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
|
||||
// purpose and history
|
||||
// -------------------
|
||||
|
||||
// our goal is to expose any memory handling bugs in the application as
|
||||
// early as possible. various checks are performed upon each memory API call;
|
||||
// if all options are on, we can spot the following:
|
||||
// memory leaks, double-free, allocation over/underruns,
|
||||
// unused memory, and use-after-free.
|
||||
//
|
||||
// this code started life as Paul Nettle's memory manager (available
|
||||
// at http://www.fluidstudios.com), and has been completely overhauled.
|
||||
// in particular, it is now thread-safe and modularized;
|
||||
// duplicated code has been eliminated.
|
||||
//
|
||||
//
|
||||
// instructions for integrating into your project
|
||||
// ----------------------------------------------
|
||||
//
|
||||
// 1) #include this from all project source files [that will allocate memory].
|
||||
// doing so from the precompiled header is recommended, since the
|
||||
// compiler will make sure it has actually been included.
|
||||
// 2) all system headers must be #include-d before this header, so that
|
||||
// we don't mess with any of their local operator new/delete.
|
||||
// 3) if project source/headers also use local operator new/delete, #include
|
||||
// "nommgr.h" before that spot, and re-#include "mmgr.h" afterwards.
|
||||
//
|
||||
// 4) if using MFC:
|
||||
// - set linker option /FORCE - works around conflict between our global
|
||||
// operator new and that of MFC. be sure to check for other errors.
|
||||
// - remove any #define new DEBUG_NEW from all source files.
|
||||
//
|
||||
//
|
||||
// effects
|
||||
// -------
|
||||
//
|
||||
// many bugs are caught and announced with no further changes
|
||||
// required, due to integrity checks inside the allocator.
|
||||
//
|
||||
// at exit, three report files are generated: a listing of leaks,
|
||||
// various statistics (e.g. total unused memory), and the log.
|
||||
// this lists (depending on settings) all allocations, enter/exit
|
||||
// indications for our functions, and failure notifications.
|
||||
//
|
||||
//
|
||||
// digging deeper
|
||||
// --------------
|
||||
//
|
||||
// when tracking down hard-to-find bugs, more stringent checks can be
|
||||
// activated via mmgr_set_option, or by changing the initial value of
|
||||
// options in mmgr.cpp. however, they slow down the app considerably
|
||||
// and need not always be enabled. see option declarations above.
|
||||
//
|
||||
// you can also change padding_size in mmgr.cpp at compile-time to provide
|
||||
// more safety vs. overruns, at the cost of wasting lots of memory per
|
||||
// allocation (which must also be cleared). this is only done in
|
||||
// PARANOIA builds, because overruns seldom 'skip' padding.
|
||||
//
|
||||
// finally, you can induce memory allocations to fail a certain percentage
|
||||
// of the time - this tests your application's error handling.
|
||||
// adjust the RANDOM_FAILURE #define in mmgr.cpp.
|
||||
//
|
||||
//
|
||||
// fixing your bugs
|
||||
// ----------------
|
||||
//
|
||||
// if this code crashes or fails an debug_assert, it is most likely due to a bug
|
||||
// in your application. consult the current Alloc for information;
|
||||
// search the log for its address to determine what operation failed,
|
||||
// and what piece of code owns the allocation.
|
||||
//
|
||||
// if the cause isn't visible (i.e. the error is reported after the fact),
|
||||
// you can try activating the more stringent checks to catch the problem
|
||||
// earlier. you may also call the validation routines at checkpoints
|
||||
// in your code to narrow the cause down. if all else fails, break on
|
||||
// the allocation number to see what's happening.
|
||||
//
|
||||
// good luck!
|
||||
#endif // #if CONFIG_USE_MMGR
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
// remove all memory allocation "hooks"
|
||||
// remove all of mmgr.h's memory allocation "hooks" -
|
||||
// but only if we actually defined them!
|
||||
#if CONFIG_USE_MMGR || HAVE_VC_DEBUG_ALLOC
|
||||
|
||||
#undef new
|
||||
#undef delete
|
||||
@ -10,3 +12,5 @@
|
||||
#undef strdup
|
||||
#undef wcsdup
|
||||
#undef getcwd
|
||||
|
||||
#endif
|
||||
|
@ -48,7 +48,7 @@ need only be renamed (e.g. _open, _stat).
|
||||
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
|
||||
#include "sysdep/win/wposix.h"
|
||||
#include "sysdep/win/win.h"
|
||||
@ -81,4 +81,4 @@ need only be renamed (e.g. _open, _stat).
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#endif // #ifdef _WIN32
|
||||
#endif // #if OS_WIN
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
# include "sysdep/win/wposix_types.h"
|
||||
#else
|
||||
// unix/linux/glibc/gcc says that this macro has to be defined when including
|
||||
@ -16,4 +16,4 @@
|
||||
# define __STDC_LIMIT_MACROS
|
||||
# endif
|
||||
# include <stdint.h>
|
||||
#endif // #ifdef _WIN32
|
||||
#endif // #if OS_WIN
|
||||
|
@ -8,17 +8,30 @@
|
||||
//
|
||||
// this policy yields the best compile performance with or without PCH.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// must come before warning disables.
|
||||
#include "lib/config.h"
|
||||
|
||||
// disable some common and annoying warnings
|
||||
// (done as soon as possible so that headers below are covered)
|
||||
#if MSC_VERSION
|
||||
// .. temporarily disabled W4 (unimportant but ought to be fixed)
|
||||
# pragma warning(disable:4201) // nameless struct (Matrix3D)
|
||||
# pragma warning(disable:4244) // conversion from uintN to uint8
|
||||
// .. permanently disabled W4
|
||||
# pragma warning(disable:4127) // conditional expression is constant; rationale: see STMT in lib.h.
|
||||
# pragma warning(disable:4996) // function is deprecated
|
||||
# pragma warning(disable:4786) // identifier truncated to 255 chars
|
||||
# if _MSC_VER >= 1400 // VS2005 code analysis warnings - disable the very frequent ones:
|
||||
// .. VS2005 code analysis (very frequent ones)
|
||||
# if MSC_VERSION >= 1400
|
||||
# pragma warning(disable:6011) // dereferencing NULL pointer
|
||||
# pragma warning(disable:6246) // local declaration hides declaration of the same name in outer scope
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// make these available everywhere for convenience:
|
||||
#include "lib/config.h"
|
||||
//
|
||||
// headers made available everywhere for convenience
|
||||
//
|
||||
|
||||
#include "lib/types.h"
|
||||
#include "lib/string_s.h" // CRT secure string
|
||||
#include "lib/debug.h"
|
||||
@ -33,15 +46,13 @@
|
||||
// come before the memory tracker headers to avoid conflicts with their
|
||||
// macros. therefore, they are always included, even if !HAVE_PCH.
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <crtdbg.h>
|
||||
#if OS_WIN
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
#include <malloc.h>
|
||||
#include <new>
|
||||
#include <memory>
|
||||
#include <cstring> // uses placement new
|
||||
#include <string>
|
||||
#include <valarray> // free() member function
|
||||
|
||||
|
||||
//
|
||||
@ -58,7 +69,7 @@
|
||||
// not otherwise need some of these headers. therefore, do nothing and rely
|
||||
// on all source files (additionally) including everything they need.
|
||||
|
||||
#ifdef HAVE_PCH
|
||||
#if HAVE_PCH
|
||||
|
||||
// all new-form C library headers
|
||||
#include <cassert>
|
||||
@ -119,7 +130,7 @@
|
||||
#include <valarray>
|
||||
|
||||
// STL extensions
|
||||
#ifdef __GNUC__
|
||||
#if GCC_VERSION
|
||||
# include <ext/hash_map>
|
||||
# include <ext/hash_set>
|
||||
#else
|
||||
@ -127,19 +138,17 @@
|
||||
# include <hash_set>
|
||||
#endif
|
||||
|
||||
|
||||
// CStr is included very frequently, so a reasonable amount of time is saved
|
||||
// by including it here. (~10% in a full rebuild, as of r2365)
|
||||
// some other external libraries that are used in several places:
|
||||
// .. CStr is included very frequently, so a reasonable amount of time is
|
||||
// saved by including it here. (~10% in a full rebuild, as of r2365)
|
||||
#include "ps/CStr.h"
|
||||
|
||||
// Some other external libraries that are used in several places:
|
||||
#include "scripting/SpiderMonkey.h"
|
||||
#include "boost/shared_ptr.hpp"
|
||||
#include "boost/weak_ptr.hpp"
|
||||
|
||||
// (further headers to be precompiled go here)
|
||||
|
||||
#endif // #ifdef HAVE_PCH
|
||||
#endif // #if HAVE_PCH
|
||||
|
||||
|
||||
//
|
||||
@ -150,17 +159,7 @@
|
||||
// are hooked. placing in the precompiled header is more convenient than
|
||||
// manually #including from every file, but requires that all system
|
||||
// headers containing "new", "malloc" etc. come before this (see above).
|
||||
|
||||
// use custom memory tracker (lib/mmgr.cpp)
|
||||
#if defined(CONFIG_USE_MMGR)
|
||||
//
|
||||
// note: mmgr.h activates mmgr or the VC debug heap or nothing depending
|
||||
// on CONFIG_USE_MMGR and HAVE_VC_DEBUG_ALLOC settings.
|
||||
# include "mmgr.h"
|
||||
// use VC debug heap (superceded by mmgr; it remains for completeness)
|
||||
#elif defined(HAVE_VC_DEBUG_ALLOC)
|
||||
// can't define _CRTDBG_MAP_ALLOC because crtdbg.h has a broken 'new',
|
||||
// so manually redefine the appropriate functions.
|
||||
# define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
# define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
# define calloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
# define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
# define free(p) _free_dbg(p, _NORMAL_BLOCK)
|
||||
#endif
|
||||
|
@ -5,13 +5,14 @@
|
||||
|
||||
#define USE_WINDOWS_CURSOR
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
#include "lib/sysdep/win/win_internal.h"
|
||||
#endif
|
||||
|
||||
#include "res.h"
|
||||
#include "ogl_tex.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "sysdep/sysdep.h"
|
||||
|
||||
struct ogl_cursor {
|
||||
Handle tex;
|
||||
@ -37,7 +38,7 @@ struct ogl_cursor {
|
||||
|
||||
extern int g_mouse_x, g_mouse_y;
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
// On Windows, allow runtime choice between Windows cursors and OpenGL
|
||||
// cursors (Windows = more responsive, OpenGL = more consistent with what
|
||||
// the game sees)
|
||||
@ -49,18 +50,18 @@ struct Cursor
|
||||
};
|
||||
char type; // 0 for OpenGL cursor, 1 for Windows cursor
|
||||
};
|
||||
#else // #ifdef _WIN32
|
||||
#else // #if OS_WIN
|
||||
struct Cursor
|
||||
{
|
||||
ogl_cursor* cursor; // font texture
|
||||
};
|
||||
#endif // #ifdef _WIN32 / #else
|
||||
#endif // #if OS_WIN / #else
|
||||
|
||||
H_TYPE_DEFINE(Cursor);
|
||||
|
||||
static void Cursor_init(Cursor* c, va_list)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
# ifdef USE_WINDOWS_CURSOR
|
||||
c->type = 1;
|
||||
# else
|
||||
@ -74,14 +75,14 @@ static void Cursor_init(Cursor* c, va_list)
|
||||
|
||||
static void Cursor_dtor(Cursor* c)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
if (c->type == 1)
|
||||
{
|
||||
if (c->wincursor)
|
||||
DestroyIcon(c->wincursor);
|
||||
}
|
||||
else
|
||||
#endif // _WIN32
|
||||
#endif
|
||||
{
|
||||
if (c->cursor)
|
||||
{
|
||||
@ -92,100 +93,10 @@ static void Cursor_dtor(Cursor* c)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static void* ptr_from_HICON(HICON hIcon)
|
||||
{
|
||||
return (void*)(uintptr_t)hIcon;
|
||||
}
|
||||
|
||||
static HICON HICON_from_ptr(void* p)
|
||||
{
|
||||
return (HICON)(uintptr_t)p;
|
||||
}
|
||||
|
||||
static int cursor_load(Handle ht, int hotspotx, int hotspoty, void** sysdep_cursor)
|
||||
{
|
||||
int ret = -1;
|
||||
*sysdep_cursor = 0;
|
||||
|
||||
void* bgra_mem = 0;
|
||||
|
||||
{
|
||||
// get format
|
||||
int w, h, fmt, bpp;
|
||||
const u8* imgdata;
|
||||
CHECK_ERR(tex_info(ht, &w, &h, &fmt, &bpp, (void**)&imgdata));
|
||||
if(bpp != 32 || (fmt != GL_BGRA && fmt != GL_RGBA))
|
||||
{
|
||||
debug_warn("Cursor texture not 32-bit RGBA/BGRA");
|
||||
ret = ERR_TEX_FMT_INVALID;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// convert to BGRA if not already in that format (required by BMP)
|
||||
if(fmt != GL_BGRA)
|
||||
{
|
||||
// don't convert in-place so we don't spoil someone else's
|
||||
// use of the texture (however unlikely that may be).
|
||||
bgra_mem = malloc(w*h*4);
|
||||
if(!bgra_mem)
|
||||
{
|
||||
ret = ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
const u8* src = imgdata;
|
||||
u8* dst = (u8*)bgra_mem;
|
||||
for(int i = 0; i < w*h; i++)
|
||||
{
|
||||
const u8 r = src[0], g = src[1], b = src[2], a = src[3];
|
||||
dst[0] = b; dst[1] = g; dst[2] = r; dst[3] = a;
|
||||
dst += 4;
|
||||
src += 4;
|
||||
}
|
||||
imgdata = (const u8*)bgra_mem;
|
||||
}
|
||||
|
||||
HBITMAP hbmColor = CreateBitmap(w, h, 1, 32, imgdata);
|
||||
|
||||
// CreateIconIndirect doesn't access it; we just need to pass
|
||||
// an empty bitmap.
|
||||
HBITMAP hbmMask = CreateBitmap(w, h, 1, 1, 0);
|
||||
|
||||
ICONINFO ii;
|
||||
ii.fIcon = FALSE; // cursor
|
||||
ii.xHotspot = hotspotx;
|
||||
ii.yHotspot = hotspoty;
|
||||
ii.hbmMask = hbmMask;
|
||||
ii.hbmColor = hbmColor;
|
||||
HICON hIcon = CreateIconIndirect(&ii);
|
||||
|
||||
// CreateIconIndirect makes copies, so we no longer need these.
|
||||
DeleteObject(hbmMask);
|
||||
DeleteObject(hbmColor);
|
||||
|
||||
if(!hIcon) // not INVALID_HANDLE_VALUE
|
||||
{
|
||||
debug_warn("cursor CreateIconIndirect failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*sysdep_cursor = ptr_from_HICON(hIcon);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
fail:
|
||||
free(bgra_mem);
|
||||
|
||||
CHECK_ERR(ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int Cursor_reload(Cursor* c, const char* name, Handle)
|
||||
{
|
||||
char filename[VFS_MAX_PATH];
|
||||
int ret;
|
||||
|
||||
// Load the .txt file containing the pixel offset of
|
||||
// the cursor's hotspot (the bit of it that's
|
||||
@ -209,18 +120,29 @@ static int Cursor_reload(Cursor* c, const char* name, Handle)
|
||||
Handle ht = tex_load(filename);
|
||||
CHECK_ERR(ht);
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
if (c->type == 1)
|
||||
{
|
||||
int err = cursor_load(ht, hotspotx, hotspoty, (void**)&c->wincursor);
|
||||
if(err < 0)
|
||||
int w, h, gl_fmt, bpp;
|
||||
void* img;
|
||||
if(tex_info(ht, &w, &h, &gl_fmt, &bpp, &img) < 0 ||
|
||||
(bpp != 32 || gl_fmt != GL_RGBA))
|
||||
{
|
||||
debug_warn("Cursor_reload: invalid texture format");
|
||||
ret = ERR_TEX_FMT_INVALID;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = cursor_create(w, h, img, hotspotx, hotspoty, (void**)&c->wincursor);
|
||||
if(ret < 0)
|
||||
{
|
||||
fail:
|
||||
tex_free(ht);
|
||||
return err;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif // _WIN32
|
||||
#endif
|
||||
{
|
||||
int err = tex_upload(ht, GL_NEAREST);
|
||||
CHECK_ERR(err);
|
||||
@ -254,7 +176,7 @@ void cursor_draw(const char* name)
|
||||
// Use 'null' to disable the cursor
|
||||
if (!name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
#endif
|
||||
return;
|
||||
@ -268,13 +190,13 @@ void cursor_draw(const char* name)
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
if (c->type == 1)
|
||||
{
|
||||
SetCursor(c->wincursor);
|
||||
}
|
||||
else
|
||||
#endif // _WIN32
|
||||
#endif
|
||||
{
|
||||
c->cursor->draw(g_mouse_x, g_yres - g_mouse_y);
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ static i32 last_in_use = -1; // don't search unused entries
|
||||
static HDATA* h_data_from_idx(const i32 idx)
|
||||
{
|
||||
// makes things *crawl*!
|
||||
#ifdef PARANOIA
|
||||
#if CONFIG_PARANOIA
|
||||
debug_heap_check();
|
||||
#endif
|
||||
|
||||
@ -283,7 +283,7 @@ static int alloc_idx(i32& idx, HDATA*& hd)
|
||||
// add another
|
||||
if(last_in_use >= hdata_cap)
|
||||
{
|
||||
debug_assert(!"alloc_idx: too many open handles (increase IDX_BITS)");
|
||||
debug_warn("alloc_idx: too many open handles (increase IDX_BITS)");
|
||||
return ERR_LIMIT;
|
||||
}
|
||||
idx = last_in_use+1; // just incrementing idx would start it at 1
|
||||
@ -418,11 +418,22 @@ int h_free(Handle& h, H_Type type)
|
||||
i32 idx = h_idx(h);
|
||||
HDATA* hd = h_data_tag_type(h, type);
|
||||
|
||||
// wipe out the handle, to prevent reuse.
|
||||
// wipe out the handle to prevent reuse but keep a copy for below.
|
||||
const Handle h_copy = h;
|
||||
h = 0;
|
||||
|
||||
// h was invalid
|
||||
if(!hd)
|
||||
return ERR_INVALID_HANDLE;
|
||||
{
|
||||
// 0-initialized or an error code; don't complain because this
|
||||
// happens often and is harmless.
|
||||
if(h_copy <= 0)
|
||||
return 0;
|
||||
// this was a valid handle but was probably freed in the meantime.
|
||||
// complain because this probably indicates a bug somewhere.
|
||||
CHECK_ERR(ERR_INVALID_HANDLE);
|
||||
}
|
||||
|
||||
return h_free_idx(idx, hd);
|
||||
}
|
||||
|
||||
@ -606,18 +617,21 @@ skip_alloc:
|
||||
|
||||
H_VTbl* vtbl = type;
|
||||
|
||||
int err;
|
||||
|
||||
// init
|
||||
va_list args;
|
||||
va_start(args, flags);
|
||||
if(vtbl->init)
|
||||
{
|
||||
vtbl->init(hd->user, args);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
// reload
|
||||
if(vtbl->reload)
|
||||
{
|
||||
// catch exception to simplify reload funcs - let them use new()
|
||||
int err;
|
||||
try
|
||||
{
|
||||
err = vtbl->reload(hd->user, fn, h);
|
||||
@ -626,19 +640,20 @@ skip_alloc:
|
||||
{
|
||||
err = ERR_NO_MEM;
|
||||
}
|
||||
|
||||
// reload failed; free the handle
|
||||
if(err < 0)
|
||||
{
|
||||
// don't cache it - it's not valid
|
||||
hd->keep_open = 0;
|
||||
|
||||
h_free(h, type);
|
||||
return (Handle)err;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return h;
|
||||
|
||||
fail:
|
||||
// reload failed; free the handle
|
||||
hd->keep_open = 0; // disallow caching (since contents are invalid)
|
||||
(void)h_free(h, type); // (h_free already does WARN_ERR)
|
||||
|
||||
// note: since some uses will always fail (e.g. loading sounds if
|
||||
// g_Quickstart), do not complain here.
|
||||
return (Handle)err;
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ typedef MemSrcMgr* SrcPtr;
|
||||
* before any data is actually read.
|
||||
*/
|
||||
|
||||
METHODDEF(void) init_source(j_decompress_ptr cinfo)
|
||||
METHODDEF(void) init_source(j_decompress_ptr UNUSED(cinfo))
|
||||
{
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ METHODDEF(void) skip_input_data(j_decompress_ptr cinfo, long num_bytes)
|
||||
* for error exit.
|
||||
*/
|
||||
|
||||
METHODDEF(void) term_source(j_decompress_ptr cinfo)
|
||||
METHODDEF(void) term_source(j_decompress_ptr UNUSED(cinfo))
|
||||
{
|
||||
/*
|
||||
* no-op (we don't own the buffer and shouldn't,
|
||||
@ -318,7 +318,7 @@ METHODDEF(void) term_destination(j_compress_ptr cinfo)
|
||||
|
||||
// make sure any data left in the buffer is written out
|
||||
const size_t bytes_in_buf = OUTPUT_BUF_SIZE - dst->pub.free_in_buffer;
|
||||
if(vfs_io(dst->hf, bytes_in_buf, (void**)&dst->buf) != bytes_in_buf)
|
||||
if(vfs_io(dst->hf, bytes_in_buf, (void**)&dst->buf) != (ssize_t)bytes_in_buf)
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
|
||||
// flush file, if necessary.
|
||||
|
@ -149,10 +149,8 @@ static void Mem_dtor(Mem* m)
|
||||
|
||||
// can't alloc here, because h_alloc needs the key when called
|
||||
// (key == pointer we allocate)
|
||||
static int Mem_reload(Mem* m, const char* fn, Handle hm)
|
||||
static int Mem_reload(Mem* m, const char* UNUSED(fn), Handle hm)
|
||||
{
|
||||
UNUSED(fn);
|
||||
|
||||
set_alloc(m->raw_p, hm);
|
||||
return 0;
|
||||
}
|
||||
@ -168,11 +166,8 @@ static int Mem_reload(Mem* m, const char* fn, Handle hm)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static void heap_free(void* raw_p, size_t raw_size, uintptr_t ctx)
|
||||
static void heap_free(void* raw_p, size_t UNUSED(raw_size), uintptr_t UNUSED(ctx))
|
||||
{
|
||||
UNUSED(raw_size);
|
||||
UNUSED(ctx);
|
||||
|
||||
free(raw_p);
|
||||
}
|
||||
|
||||
@ -187,16 +182,14 @@ static void* heap_alloc(size_t raw_size, uintptr_t& ctx)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/*
|
||||
static u8* pool;
|
||||
static size_t pool_pos;
|
||||
static const size_t POOL_CAP = 8*MiB; // TODO: user editable
|
||||
|
||||
|
||||
static void pool_free(void* raw_p, size_t raw_size, uintptr_t ctx)
|
||||
static void pool_free(void* UNUSED(raw_p), size_t raw_size, uintptr_t ctx)
|
||||
{
|
||||
UNUSED(raw_p);
|
||||
|
||||
size_t ofs = (size_t)ctx;
|
||||
|
||||
// at or beyond current next-alloc position: invalid
|
||||
@ -213,7 +206,7 @@ static void pool_free(void* raw_p, size_t raw_size, uintptr_t ctx)
|
||||
|
||||
static void* pool_alloc(const size_t raw_size, uintptr_t& ctx)
|
||||
{
|
||||
ctx = ~0; // make sure it's invalid if we fail
|
||||
ctx = ~0U; // make sure it's invalid if we fail
|
||||
|
||||
if(!pool)
|
||||
{
|
||||
@ -233,7 +226,7 @@ static void* pool_alloc(const size_t raw_size, uintptr_t& ctx)
|
||||
void* raw_p = (u8*)pool + ctx;
|
||||
return raw_p;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include "ogghack.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
# ifdef NDEBUG
|
||||
# pragma comment(lib, "vorbisfile.lib")
|
||||
# else
|
||||
@ -78,12 +78,12 @@ size_t read_func(void* ptr, size_t elements, size_t el_size, void* datasource)
|
||||
}
|
||||
|
||||
|
||||
int seek_func(void* datasource, ogg_int64_t offset, int whence)
|
||||
int seek_func(void* UNUSED(datasource), ogg_int64_t UNUSED(offset), int UNUSED(whence))
|
||||
{
|
||||
return -1; // libvorbisfile: indicate "not implemented"
|
||||
}
|
||||
|
||||
int close_func(void* datasource)
|
||||
int close_func(void* UNUSED(datasource))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -128,7 +128,7 @@ void ogg_open(void* _o, ALenum& fmt, ALsizei& freq)
|
||||
void* datasource = &o->incoming_bufs;
|
||||
if(ov_open_callbacks(datasource, &o->oggStream, NULL, 0, cbs) < 0)
|
||||
{
|
||||
debug_assert(!"ov_open failed");
|
||||
debug_warn("ov_open failed");
|
||||
}
|
||||
|
||||
o->vorbisInfo = ov_info(&o->oggStream, -1);
|
||||
@ -166,7 +166,7 @@ size_t ogg_read(void* _o, void* buf, size_t max_size)
|
||||
if(result > 0)
|
||||
bytes_written += result;
|
||||
else if(result < 0)
|
||||
debug_assert(!"ogg read error");
|
||||
debug_warn("ogg read error");
|
||||
// clean break - end of data
|
||||
else
|
||||
break;
|
||||
|
@ -28,9 +28,24 @@ static bool fmt_is_s3tc(GLenum fmt)
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool filter_is_known(GLint filter)
|
||||
{
|
||||
switch(filter)
|
||||
{
|
||||
case GL_NEAREST:
|
||||
case GL_LINEAR:
|
||||
case GL_NEAREST_MIPMAP_NEAREST:
|
||||
case GL_LINEAR_MIPMAP_NEAREST:
|
||||
case GL_NEAREST_MIPMAP_LINEAR:
|
||||
case GL_LINEAR_MIPMAP_LINEAR:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -61,7 +76,7 @@ static int get_gl_fmt(int bpp, int flags, GLenum* fmt, GLenum* int_fmt)
|
||||
{
|
||||
const bool alpha = (flags & TEX_ALPHA) != 0;
|
||||
const bool bgr = (flags & TEX_BGR ) != 0;
|
||||
const bool gray = (flags & TEX_GRAY ) != 0;
|
||||
const bool grey = (flags & TEX_GREY ) != 0;
|
||||
const int dxt = flags & TEX_DXT;
|
||||
|
||||
// in case we fail
|
||||
@ -101,6 +116,7 @@ static int get_gl_fmt(int bpp, int flags, GLenum* fmt, GLenum* int_fmt)
|
||||
switch(bpp)
|
||||
{
|
||||
case 8:
|
||||
debug_assert(grey);
|
||||
*fmt = GL_LUMINANCE;
|
||||
*int_fmt = high_quality? GL_LUMINANCE8 : GL_LUMINANCE4;
|
||||
return 0;
|
||||
@ -125,8 +141,7 @@ static int get_gl_fmt(int bpp, int flags, GLenum* fmt, GLenum* int_fmt)
|
||||
return ERR_TEX_FMT_INVALID;
|
||||
}
|
||||
|
||||
// unreachable
|
||||
debug_assert(0);
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
|
||||
@ -187,10 +202,8 @@ struct Tex
|
||||
|
||||
H_TYPE_DEFINE(Tex);
|
||||
|
||||
static void Tex_init(Tex* t, va_list args)
|
||||
static void Tex_init(Tex* t, va_list UNUSED(args))
|
||||
{
|
||||
UNUSED(args);
|
||||
|
||||
// set to default (once)
|
||||
t->filter = tex_filter;
|
||||
}
|
||||
@ -321,8 +334,10 @@ static int tex_validate(const uint line, const Tex* t)
|
||||
|
||||
// upload parameters, set by tex_upload(Handle), or 0
|
||||
GLint filter = t->filter;
|
||||
GLenum int_fmt = t->int_fmt;
|
||||
// TODO: check if valid
|
||||
if(filter != 0 && !filter_is_known(filter))
|
||||
msg = "invalid filter";
|
||||
// as with the texel format above, there is not anything we can do
|
||||
// to verify t->int_fmt is correct (even 0 is valid).
|
||||
|
||||
if(msg)
|
||||
{
|
||||
@ -367,7 +382,7 @@ int tex_upload(const Handle ht, int filter_ovr, int int_fmt_ovr, int fmt_ovr)
|
||||
GLenum fmt = t->fmt;
|
||||
GLint filter = t->filter;
|
||||
GLenum int_fmt = t->int_fmt;
|
||||
void* tex_data = (char*)mem_get_ptr(t->ti.hm) + t->ti.ofs;
|
||||
void* tex_data = (u8*)mem_get_ptr(t->ti.hm) + t->ti.ofs;
|
||||
|
||||
// does filter call for uploading mipmaps?
|
||||
const bool need_mipmaps = filter_uses_mipmaps(filter);
|
||||
@ -539,7 +554,7 @@ int tex_info(Handle ht, int* w, int* h, int* fmt, int* bpp, void** p)
|
||||
if(bpp)
|
||||
*bpp = t->ti.bpp;
|
||||
if(p)
|
||||
*p = mem_get_ptr(t->ti.hm);
|
||||
*p = (u8*)mem_get_ptr(t->ti.hm) + t->ti.ofs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -36,12 +36,12 @@
|
||||
#endif
|
||||
|
||||
// for AL_FORMAT_VORBIS_EXT decl on Linux
|
||||
#ifdef OS_LINUX
|
||||
#if OS_LINUX
|
||||
# include <AL/alexttypes.h>
|
||||
#endif
|
||||
|
||||
// for DLL-load hack in alc_init
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
# include "sysdep/win/win_internal.h"
|
||||
#endif
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
#define OGG_HACK
|
||||
#include "ogghack.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
# pragma comment(lib, "openal32.lib")
|
||||
# pragma comment(lib, "alut.lib") // alutLoadWAVMemory
|
||||
#endif
|
||||
@ -201,7 +201,7 @@ static int alc_init()
|
||||
// thus speeding up startup by 100..400 ms. everything works ATM;
|
||||
// hopefully, OpenAL doesn't rely on them actually being unloaded.
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
HMODULE dlls[3];
|
||||
dlls[0] = LoadLibrary("wrap_oal.dll");
|
||||
dlls[1] = LoadLibrary("setupapi.dll");
|
||||
@ -213,7 +213,7 @@ static int alc_init()
|
||||
// (it's not caused by the DLL load hack above). everything works and
|
||||
// we can continue normally; we just need to catch it to prevent the
|
||||
// unhandled exception filter from reporting it.
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
__try
|
||||
{
|
||||
alc_dev = alcOpenDevice((ALubyte*)alc_dev_name);
|
||||
@ -245,7 +245,7 @@ static int alc_init()
|
||||
}
|
||||
|
||||
// release DLL references, so BoundsChecker doesn't complain at exit.
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
for(int i = 0; i < ARRAY_SIZE(dlls); i++)
|
||||
if(dlls[i] != INVALID_HANDLE_VALUE)
|
||||
FreeLibrary(dlls[i]);
|
||||
|
@ -51,7 +51,7 @@ extern "C" {
|
||||
EXTERN(void) jpeg_mem_src(j_decompress_ptr cinfo, void* p, size_t size);
|
||||
EXTERN(void) jpeg_vfs_dst(j_compress_ptr cinfo, Handle hf);
|
||||
}
|
||||
# ifdef _MSC_VER
|
||||
# if MSC_VERSION
|
||||
# ifdef NDEBUG
|
||||
# pragma comment(lib, "jpeg-6b.lib")
|
||||
# else
|
||||
@ -62,7 +62,7 @@ EXTERN(void) jpeg_vfs_dst(j_compress_ptr cinfo, Handle hf);
|
||||
|
||||
|
||||
#ifndef NO_PNG
|
||||
# ifdef _WIN32
|
||||
# if OS_WIN
|
||||
// to avoid conflicts, windows.h must not be included.
|
||||
// libpng pulls it in for WINAPI; we prevent the include
|
||||
// and define that here.
|
||||
@ -71,19 +71,26 @@ EXTERN(void) jpeg_vfs_dst(j_compress_ptr cinfo, Handle hf);
|
||||
# define WINAPIV __cdecl
|
||||
// different header name, too.
|
||||
# include <libpng13/png.h>
|
||||
# ifdef _MSC_VER
|
||||
# if MSC_VERSION
|
||||
# ifdef NDEBUG
|
||||
# pragma comment(lib, "libpng13.lib")
|
||||
# else
|
||||
# pragma comment(lib, "libpng13d.lib")
|
||||
# endif // NDEBUG
|
||||
# endif // _MSC_VER
|
||||
# else // _WIN32
|
||||
# endif // MSC_VERSION
|
||||
# else // i.e. !OS_WIN
|
||||
# include <png.h>
|
||||
# endif // _WIN32
|
||||
# endif // OS_WIN
|
||||
#endif // NO_PNG
|
||||
|
||||
|
||||
// squelch "dtor / setjmp interaction" warnings.
|
||||
// all attempts to resolve the underlying problem failed; apparently
|
||||
// the warning is generated if setjmp is used at all in C++ mode.
|
||||
// (png_decode has no code that would trigger ctors/dtors, nor are any
|
||||
// called in its prolog/epilog code).
|
||||
#if MSC_VERSION
|
||||
# pragma warning(disable: 4611)
|
||||
#endif
|
||||
|
||||
|
||||
#define CODEC(name) { name##_fmt, name##_ext, name##_decode, name##_encode, #name}
|
||||
@ -298,23 +305,23 @@ static int write_img(const char* fn, const void* hdr, size_t hdr_size,
|
||||
static int fmt_8_or_24_or_32(int bpp, int flags)
|
||||
{
|
||||
const bool alpha = (flags & TEX_ALPHA) != 0;
|
||||
const bool gray = (flags & TEX_GRAY ) != 0;
|
||||
const bool grey = (flags & TEX_GREY ) != 0;
|
||||
const bool dxt = (flags & TEX_DXT ) != 0;
|
||||
|
||||
if(dxt)
|
||||
return ERR_TEX_FMT_INVALID;
|
||||
|
||||
// if gray,
|
||||
if(gray)
|
||||
// if grey..
|
||||
if(grey)
|
||||
{
|
||||
// and 8bpp / no alpha, it's ok.
|
||||
if(bpp == 8 && !alpha)
|
||||
return 0;
|
||||
|
||||
// .. otherwise, it's invalid
|
||||
// otherwise, it's invalid.
|
||||
return ERR_TEX_FMT_INVALID;
|
||||
}
|
||||
// it's not gray.
|
||||
// it's not grey.
|
||||
|
||||
if(bpp == 24 && !alpha)
|
||||
return 0;
|
||||
@ -386,7 +393,7 @@ DDSURFACEDESC2;
|
||||
|
||||
static inline bool dds_fmt(const u8* ptr, size_t size)
|
||||
{
|
||||
UNUSED(size); // size >= 4, we only need 4 bytes
|
||||
UNUSED2(size); // size >= 4, we only need 4 bytes
|
||||
|
||||
return *(u32*)ptr == FOURCC('D','D','S',' ');
|
||||
}
|
||||
@ -463,8 +470,8 @@ fail:
|
||||
if(mipmaps)
|
||||
flags |= TEX_MIPMAPS;
|
||||
|
||||
// if(file_size != hdr_size + img_size)
|
||||
// err = "file size mismatch";
|
||||
if(file_size < hdr_size + img_size)
|
||||
err = "file size too small";
|
||||
if(w % 4 || h % 4)
|
||||
err = "image dimensions not padded to S3TC block size";
|
||||
if(!w || !h)
|
||||
@ -490,7 +497,7 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
static int dds_encode(TexInfo* t, const char* fn, u8* img, size_t img_size)
|
||||
static int dds_encode(TexInfo* UNUSED(t), const char* UNUSED(fn), u8* UNUSED(img), size_t UNUSED(img_size))
|
||||
{
|
||||
return ERR_NOT_IMPLEMENTED;
|
||||
}
|
||||
@ -512,7 +519,7 @@ static int dds_encode(TexInfo* t, const char* fn, u8* img, size_t img_size)
|
||||
enum TgaImgType
|
||||
{
|
||||
TGA_TRUE_COLOR = 2, // uncompressed 24 or 32 bit direct RGB
|
||||
TGA_GRAY = 3 // uncompressed 8 bit direct grayscale
|
||||
TGA_GREY = 3 // uncompressed 8 bit direct greyscale
|
||||
};
|
||||
|
||||
enum TgaImgDesc
|
||||
@ -550,7 +557,7 @@ TgaHeader;
|
||||
// we can only check if the first 4 bytes are valid
|
||||
static inline bool tga_fmt(const u8* ptr, size_t size)
|
||||
{
|
||||
UNUSED(size);
|
||||
UNUSED2(size); // size >= 4, we only need 4 bytes
|
||||
|
||||
TgaHeader* hdr = (TgaHeader*)ptr;
|
||||
|
||||
@ -558,8 +565,8 @@ static inline bool tga_fmt(const u8* ptr, size_t size)
|
||||
if(hdr->color_map_type != 0)
|
||||
return false;
|
||||
|
||||
// wrong color type (not uncompressed grayscale or RGB)
|
||||
if(hdr->img_type != TGA_TRUE_COLOR && hdr->img_type != TGA_GRAY)
|
||||
// wrong color type (not uncompressed greyscale or RGB)
|
||||
if(hdr->img_type != TGA_TRUE_COLOR && hdr->img_type != TGA_GREY)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -604,6 +611,8 @@ fail:
|
||||
int flags = 0;
|
||||
if(alpha_bits != 0)
|
||||
flags |= TEX_ALPHA;
|
||||
if(bpp == 8)
|
||||
flags |= TEX_GREY;
|
||||
if(type == TGA_TRUE_COLOR)
|
||||
flags |= TEX_BGR;
|
||||
|
||||
@ -636,8 +645,10 @@ static int tga_encode(TexInfo* t, const char* fn, u8* img, size_t img_size)
|
||||
{
|
||||
CHECK_ERR(fmt_8_or_24_or_32(t->bpp, t->flags));
|
||||
|
||||
TgaImgDesc img_desc = (t->flags & TEX_TOP_DOWN)? TGA_TOP_DOWN : TGA_BOTTOM_UP;
|
||||
TgaImgType img_type = (t->flags & TEX_GRAY)? TGA_GRAY : TGA_TRUE_COLOR;
|
||||
u8 img_desc = (t->flags & TEX_TOP_DOWN)? TGA_TOP_DOWN : TGA_BOTTOM_UP;
|
||||
if(t->bpp == 32)
|
||||
img_desc |= 8; // size of alpha channel
|
||||
TgaImgType img_type = (t->flags & TEX_GREY)? TGA_GREY : TGA_TRUE_COLOR;
|
||||
|
||||
// transform
|
||||
int transforms = t->flags;
|
||||
@ -655,7 +666,7 @@ static int tga_encode(TexInfo* t, const char* fn, u8* img, size_t img_size)
|
||||
t->w,
|
||||
t->h,
|
||||
t->bpp,
|
||||
(u8)img_desc
|
||||
img_desc
|
||||
};
|
||||
return write_img(fn, &hdr, sizeof(hdr), img, img_size);
|
||||
}
|
||||
@ -712,7 +723,7 @@ struct BmpHeader
|
||||
|
||||
static inline bool bmp_fmt(const u8* p, size_t size)
|
||||
{
|
||||
UNUSED(size); // size >= 4, we only need 2 bytes
|
||||
UNUSED2(size); // size >= 4, we only need 2 bytes
|
||||
|
||||
// check header signature (bfType == "BM"?).
|
||||
// we compare single bytes to be endian-safe.
|
||||
@ -830,11 +841,9 @@ static int bmp_encode(TexInfo* t, const char* fn, u8* img, size_t img_size)
|
||||
|
||||
// assume bottom-up
|
||||
|
||||
static inline bool raw_fmt(const u8* p, size_t size)
|
||||
// always returns true because this is the last registered codec.
|
||||
static inline bool raw_fmt(const u8* UNUSED(p), size_t UNUSED(size))
|
||||
{
|
||||
UNUSED(p);
|
||||
UNUSED(size)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -849,32 +858,33 @@ static int raw_decode(TexInfo* t, const char* fn, u8* file, size_t file_size)
|
||||
{
|
||||
// TODO: allow 8 bit format. problem: how to differentiate from 32? filename?
|
||||
|
||||
for(uint i = 2; i <= 4; i++)
|
||||
// find a color depth that matches file_size
|
||||
uint i, dim;
|
||||
for(i = 2; i <= 4; i++)
|
||||
{
|
||||
const u32 dim = (u32)sqrtf((float)file_size/i);
|
||||
if(dim*dim*i != file_size)
|
||||
continue;
|
||||
|
||||
const int orientation = TEX_BOTTOM_UP;
|
||||
u8* const img = file;
|
||||
|
||||
// formats are: GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA
|
||||
int flags = (i == 3)? 0 : TEX_ALPHA;
|
||||
|
||||
t->ofs = 0;
|
||||
t->w = dim;
|
||||
t->h = dim;
|
||||
t->bpp = i*8;
|
||||
t->flags = flags;
|
||||
|
||||
const int transforms = orientation ^ global_orientation;
|
||||
transform(t, img, transforms);
|
||||
|
||||
return 0;
|
||||
dim = (uint)sqrtf((float)file_size/i);
|
||||
if(dim*dim*i == file_size)
|
||||
goto have_bpp;
|
||||
}
|
||||
|
||||
debug_printf("raw_decode: %s: %s\n", fn, "no matching format found");
|
||||
return -1;
|
||||
return ERR_TEX_FMT_INVALID;
|
||||
|
||||
have_bpp:
|
||||
const int orientation = TEX_BOTTOM_UP;
|
||||
u8* const img = file;
|
||||
|
||||
// formats are: GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA
|
||||
int flags = (i == 3)? 0 : TEX_ALPHA;
|
||||
|
||||
t->ofs = 0;
|
||||
t->w = dim;
|
||||
t->h = dim;
|
||||
t->bpp = i*8;
|
||||
t->flags = flags;
|
||||
|
||||
const int transforms = orientation ^ global_orientation;
|
||||
return transform(t, img, transforms);
|
||||
}
|
||||
|
||||
|
||||
@ -904,7 +914,7 @@ static int raw_encode(TexInfo* t, const char* fn, u8* img, size_t img_size)
|
||||
|
||||
static inline bool png_fmt(const u8* ptr, size_t size)
|
||||
{
|
||||
UNUSED(size); // size >= 4, we only need 4 bytes
|
||||
UNUSED2(size); // size >= 4, we only need 4 bytes
|
||||
|
||||
// don't use png_sig_cmp, so we don't pull in libpng for
|
||||
// this check alone (it might not be used later).
|
||||
@ -946,6 +956,67 @@ static void png_read(png_struct* png_ptr, u8* data, png_size_t length)
|
||||
}
|
||||
|
||||
|
||||
// split out of png_decode to simplify resource cleanup and avoid
|
||||
// "dtor / setjmp interaction" warning.
|
||||
static png_decode_impl(TexInfo* t, u8* file, size_t file_size,
|
||||
png_structp png_ptr, png_infop info_ptr,
|
||||
u8*& img, RowArray& rows, const char*& msg)
|
||||
{
|
||||
PngMemFile f = { file, file_size };
|
||||
png_set_read_fn(png_ptr, &f, png_read);
|
||||
|
||||
// read header and determine format
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
png_uint_32 w, h;
|
||||
int bit_depth, color_type;
|
||||
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0);
|
||||
const size_t pitch = png_get_rowbytes(png_ptr, info_ptr);
|
||||
const u32 bpp = (u32)(pitch / w * 8);
|
||||
|
||||
int flags = 0;
|
||||
if(bpp == 32)
|
||||
flags |= TEX_ALPHA;
|
||||
|
||||
// make sure format is acceptable
|
||||
if(bit_depth != 8)
|
||||
msg = "channel precision != 8 bits";
|
||||
if(color_type & PNG_COLOR_MASK_PALETTE)
|
||||
msg = "color type is invalid (must be direct color)";
|
||||
if(msg)
|
||||
return -1;
|
||||
|
||||
const size_t img_size = pitch * h;
|
||||
Handle img_hm;
|
||||
// cannot free old t->hm until after png_read_end,
|
||||
// but need to set to this handle afterwards => need tmp var.
|
||||
img = (u8*)mem_alloc(img_size, 64*KiB, 0, &img_hm);
|
||||
if(!img)
|
||||
return ERR_NO_MEM;
|
||||
|
||||
const int transforms = TEX_TOP_DOWN ^ global_orientation;
|
||||
CHECK_ERR(alloc_rows(img, h, pitch, transforms, rows));
|
||||
|
||||
png_read_image(png_ptr, (png_bytepp)rows);
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
|
||||
// success; make sure all data was consumed.
|
||||
debug_assert(f.p == file && f.size == file_size && f.pos == f.size);
|
||||
|
||||
// store image info
|
||||
// .. transparently switch handles - free the old (compressed)
|
||||
// buffer and replace it with the decoded-image memory handle.
|
||||
mem_free_h(t->hm);
|
||||
t->hm = img_hm;
|
||||
t->ofs = 0; // libpng returns decoded image data; no header
|
||||
t->w = w;
|
||||
t->h = h;
|
||||
t->bpp = bpp;
|
||||
t->flags = flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// limitation: palette images aren't supported
|
||||
static int png_decode(TexInfo* t, const char* fn, u8* file, size_t file_size)
|
||||
{
|
||||
@ -957,10 +1028,9 @@ static int png_decode(TexInfo* t, const char* fn, u8* file, size_t file_size)
|
||||
png_infop info_ptr = 0;
|
||||
RowArray rows = 0;
|
||||
|
||||
// freed when fail is reached:
|
||||
// freed if fail is reached:
|
||||
u8* img = 0; // decompressed image memory
|
||||
|
||||
|
||||
// allocate PNG structures; use default stderr and longjmp error handlers
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
||||
if(!png_ptr)
|
||||
@ -972,72 +1042,19 @@ static int png_decode(TexInfo* t, const char* fn, u8* file, size_t file_size)
|
||||
// setup error handling
|
||||
if(setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
// reached if PNG triggered a longjmp
|
||||
fail:
|
||||
mem_free(img);
|
||||
|
||||
debug_printf("png_decode: %s: %s\n", fn, msg? msg : "unknown");
|
||||
if(!msg)
|
||||
msg = "unknown error";
|
||||
debug_printf("png_decode: %s: %s\n", fn, msg);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
{
|
||||
PngMemFile f = { file, file_size };
|
||||
png_set_read_fn(png_ptr, &f, png_read);
|
||||
|
||||
// read header and determine format
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
png_uint_32 w, h;
|
||||
int bit_depth, color_type;
|
||||
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, 0, 0, 0);
|
||||
const size_t pitch = png_get_rowbytes(png_ptr, info_ptr);
|
||||
const u32 bpp = (u32)(pitch / w * 8);
|
||||
|
||||
int flags = 0;
|
||||
if(bpp == 32)
|
||||
flags |= TEX_ALPHA;
|
||||
|
||||
// make sure format is acceptable
|
||||
if(bit_depth != 8)
|
||||
msg = "channel precision != 8 bits";
|
||||
if(color_type & PNG_COLOR_MASK_PALETTE)
|
||||
msg = "color type is invalid (must be direct color)";
|
||||
if(msg)
|
||||
goto fail;
|
||||
|
||||
const size_t img_size = pitch * h;
|
||||
Handle img_hm;
|
||||
// cannot free old t->hm until after png_read_end,
|
||||
// but need to set to this handle afterwards => need tmp var.
|
||||
img = (u8*)mem_alloc(img_size, 64*KiB, 0, &img_hm);
|
||||
if(!img)
|
||||
{
|
||||
err = ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const int transforms = TEX_TOP_DOWN ^ global_orientation;
|
||||
int ret = alloc_rows(img, h, pitch, transforms, rows);
|
||||
if(ret < 0)
|
||||
{
|
||||
err = ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
png_read_image(png_ptr, (png_bytepp)rows);
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
|
||||
debug_assert(f.p == file && f.size == file_size && f.pos == f.size);
|
||||
|
||||
// store image info
|
||||
mem_free_h(t->hm);
|
||||
t->hm = img_hm;
|
||||
t->ofs = 0; // libpng returns decoded image data; no header
|
||||
t->w = w;
|
||||
t->h = h;
|
||||
t->bpp = bpp;
|
||||
t->flags = flags;
|
||||
|
||||
err = 0;
|
||||
}
|
||||
err = png_decode_impl(t, file, file_size, png_ptr, info_ptr, img, rows, msg);
|
||||
if(err < 0)
|
||||
goto fail;
|
||||
|
||||
// shared cleanup
|
||||
ret:
|
||||
@ -1064,11 +1081,57 @@ static void png_flush(png_structp)
|
||||
}
|
||||
|
||||
|
||||
// limitation: palette images aren't supported
|
||||
static int png_encode(TexInfo* t, const char* fn, u8* img, size_t img_size)
|
||||
// split out of png_encode to simplify resource cleanup and avoid
|
||||
// "dtor / setjmp interaction" warning.
|
||||
static int png_encode_impl(TexInfo* t, const char* fn, u8* img,
|
||||
png_structp png_ptr, png_infop info_ptr,
|
||||
RowArray& rows, Handle& hf, const char*& msg)
|
||||
{
|
||||
UNUSED(img_size);
|
||||
UNUSED2(msg); // we don't produce any error messages ATM.
|
||||
|
||||
const int png_transforms = (t->flags & TEX_BGR)? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY;
|
||||
// PNG is native RGB.
|
||||
|
||||
const png_uint_32 w = t->w, h = t->h;
|
||||
const size_t pitch = w * t->bpp / 8;
|
||||
|
||||
int color_type;
|
||||
switch(t->flags & (TEX_GREY|TEX_ALPHA))
|
||||
{
|
||||
case TEX_GREY|TEX_ALPHA:
|
||||
color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
|
||||
break;
|
||||
case TEX_GREY:
|
||||
color_type = PNG_COLOR_TYPE_GRAY;
|
||||
break;
|
||||
case TEX_ALPHA:
|
||||
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
break;
|
||||
default:
|
||||
color_type = PNG_COLOR_TYPE_RGB;
|
||||
break;
|
||||
}
|
||||
|
||||
hf = vfs_open(fn, FILE_WRITE|FILE_NO_AIO);
|
||||
CHECK_ERR(hf);
|
||||
png_set_write_fn(png_ptr, &hf, png_write, png_flush);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, w, h, 8, color_type,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
const int transforms = TEX_TOP_DOWN ^ t->flags;
|
||||
CHECK_ERR(alloc_rows(img, h, pitch, transforms, rows));
|
||||
|
||||
png_set_rows(png_ptr, info_ptr, (png_bytepp)rows);
|
||||
png_write_png(png_ptr, info_ptr, png_transforms, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// limitation: palette images aren't supported
|
||||
static int png_encode(TexInfo* t, const char* fn, u8* img, size_t UNUSED(img_size))
|
||||
{
|
||||
const char* msg = 0;
|
||||
int err = -1;
|
||||
|
||||
@ -1089,60 +1152,17 @@ static int png_encode(TexInfo* t, const char* fn, u8* img, size_t img_size)
|
||||
// setup error handling
|
||||
if(setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
// reached if libpng triggered a longjmp
|
||||
fail:
|
||||
debug_printf("png_encode: %s: %s\n", fn, msg? msg : "unknown");
|
||||
if(!msg)
|
||||
msg = "unknown error";
|
||||
debug_printf("png_encode: %s: %s\n", fn, msg);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
{
|
||||
const int png_transforms = (t->flags & TEX_BGR)? PNG_TRANSFORM_BGR : PNG_TRANSFORM_IDENTITY;
|
||||
// PNG is native RGB.
|
||||
|
||||
const png_uint_32 w = t->w, h = t->h;
|
||||
const size_t pitch = w * t->bpp / 8;
|
||||
|
||||
int color_type;
|
||||
switch(t->flags & (TEX_GRAY|TEX_ALPHA))
|
||||
{
|
||||
case TEX_GRAY|TEX_ALPHA:
|
||||
color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
|
||||
break;
|
||||
case TEX_GRAY:
|
||||
color_type = PNG_COLOR_TYPE_GRAY;
|
||||
break;
|
||||
case TEX_ALPHA:
|
||||
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
break;
|
||||
default:
|
||||
color_type = PNG_COLOR_TYPE_RGB;
|
||||
break;
|
||||
}
|
||||
|
||||
hf = vfs_open(fn, FILE_WRITE|FILE_NO_AIO);
|
||||
if(hf < 0)
|
||||
{
|
||||
err = (int)hf;
|
||||
goto fail;
|
||||
}
|
||||
png_set_write_fn(png_ptr, &hf, png_write, png_flush);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, w, h, 8, color_type,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
const int transforms = TEX_TOP_DOWN ^ t->flags;
|
||||
int ret = alloc_rows(img, h, pitch, transforms, rows);
|
||||
if(ret < 0)
|
||||
{
|
||||
err = ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
png_set_rows(png_ptr, info_ptr, (png_bytepp)rows);
|
||||
png_write_png(png_ptr, info_ptr, png_transforms, 0);
|
||||
|
||||
err = 0;
|
||||
|
||||
}
|
||||
err = png_encode_impl(t, fn, img, png_ptr, info_ptr, rows, hf, msg);
|
||||
if(err < 0)
|
||||
goto fail;
|
||||
|
||||
// shared cleanup
|
||||
ret:
|
||||
@ -1234,6 +1254,8 @@ fail:
|
||||
for(cmpt = 0; cmpt < num_cmpts; cmpt++)
|
||||
jas_matrix_destroy(matr[cmpt]);
|
||||
|
||||
// .. transparently switch handles - free the old (compressed)
|
||||
// buffer and replace it with the decoded-image memory handle.
|
||||
mem_free_h(t->hm);
|
||||
t->hm = img_hm;
|
||||
|
||||
@ -1265,7 +1287,7 @@ static int jp2_encode(TexInfo* t, const char* fn, const u8* img, size_t img_size
|
||||
|
||||
static inline bool jpg_fmt(const u8* p, size_t size)
|
||||
{
|
||||
UNUSED(size); // size >= 4, we only need 2 bytes
|
||||
UNUSED2(size); // size >= 4, we only need 2 bytes
|
||||
|
||||
// JFIF requires SOI marker at start of stream.
|
||||
// we compare single bytes to be endian-safe.
|
||||
@ -1397,14 +1419,14 @@ fail:
|
||||
// preliminary; set below to reflect output params
|
||||
|
||||
// make sure we get a color format we know
|
||||
// (exception: if bpp = 8, go grayscale below)
|
||||
// (exception: if bpp = 8, go greyscale below)
|
||||
// necessary to support non-standard CMYK files written by Photoshop.
|
||||
cinfo.out_color_space = JCS_RGB;
|
||||
|
||||
int flags = 0;
|
||||
if(bpp == 8)
|
||||
{
|
||||
flags |= TEX_GRAY;
|
||||
flags |= TEX_GREY;
|
||||
cinfo.out_color_space = JCS_GRAYSCALE;
|
||||
}
|
||||
|
||||
@ -1472,6 +1494,8 @@ fail:
|
||||
debug_printf("jpg_decode: corrupt-data warning(s) occurred\n");
|
||||
|
||||
// store image info
|
||||
// .. transparently switch handles - free the old (compressed)
|
||||
// buffer and replace it with the decoded-image memory handle.
|
||||
mem_free_h(t->hm);
|
||||
t->hm = img_hm;
|
||||
t->ofs = 0; // jpeg returns decoded image data; no header
|
||||
@ -1497,7 +1521,7 @@ ret:
|
||||
|
||||
|
||||
// limitation: palette images aren't supported
|
||||
static int jpg_encode(TexInfo* t, const char* fn, u8* img, size_t img_size)
|
||||
static int jpg_encode(TexInfo* t, const char* fn, u8* img, size_t UNUSED(img_size))
|
||||
{
|
||||
const char* msg = 0;
|
||||
int err = -1;
|
||||
@ -1675,7 +1699,7 @@ int tex_load_mem(Handle hm, const char* fn, TexInfo* t)
|
||||
size_t size;
|
||||
void* _p = mem_get_ptr(hm, &size);
|
||||
|
||||
// guarantee *_valid routines 4 header bytes
|
||||
// guarantee is_fmt routines 4 header bytes
|
||||
if(size < 4)
|
||||
return ERR_CORRUPTED;
|
||||
t->hm = hm;
|
||||
@ -1687,18 +1711,13 @@ int tex_load_mem(Handle hm, const char* fn, TexInfo* t)
|
||||
// find codec that understands the data, and decode
|
||||
const Codec* c = codecs;
|
||||
for(int i = 0; i < num_codecs; i++, c++)
|
||||
{
|
||||
if(c->is_fmt(p, size))
|
||||
{
|
||||
CHECK_ERR(c->decode(t, fn, p, size));
|
||||
|
||||
// HACK: check if the texture's data buffer is the IO buffer
|
||||
// passed to us. if so, need to increment refcount so the
|
||||
// caller's doesn't actually free it.
|
||||
if(hm == t->hm)
|
||||
h_add_ref(t->hm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_UNKNOWN_FORMAT;
|
||||
}
|
||||
@ -1711,7 +1730,8 @@ int tex_load(const char* fn, TexInfo* t)
|
||||
Handle hm = vfs_load(fn, p, size);
|
||||
RETURN_ERR(hm); // (need handle below; can't test return value directly)
|
||||
int ret = tex_load_mem(hm, fn, t);
|
||||
mem_free_h(hm);
|
||||
// do not free hm! it either still holds the image data (i.e. texture
|
||||
// wasn't compressed) or was replaced by a new buffer for the image data.
|
||||
if(ret < 0)
|
||||
memset(t, 0, sizeof(TexInfo));
|
||||
return ret;
|
||||
|
@ -28,7 +28,7 @@ enum TexInfoFlags
|
||||
TEX_DXT = 0x07, // mask; value = {1,3,5}
|
||||
TEX_BGR = 0x08,
|
||||
TEX_ALPHA = 0x10,
|
||||
TEX_GRAY = 0x20,
|
||||
TEX_GREY = 0x20,
|
||||
|
||||
// orientation - never returned by tex_load, since it automatically
|
||||
// flips to match global orientation. these are passed to tex_write
|
||||
|
@ -47,7 +47,7 @@ struct UniFont
|
||||
|
||||
H_TYPE_DEFINE(UniFont);
|
||||
|
||||
static void UniFont_init(UniFont* f, va_list UNUSEDPARAM(args))
|
||||
static void UniFont_init(UniFont* f, va_list UNUSED(args))
|
||||
{
|
||||
f->glyphs_id = new glyphmap_id;
|
||||
f->glyphs_size = new glyphmap_size;
|
||||
@ -62,7 +62,7 @@ static void UniFont_dtor(UniFont* f)
|
||||
}
|
||||
|
||||
|
||||
static int UniFont_reload(UniFont* f, const char* fn, Handle UNUSEDPARAM(h))
|
||||
static int UniFont_reload(UniFont* f, const char* fn, Handle UNUSED(h))
|
||||
{
|
||||
// fn is the base filename, e.g. "console"
|
||||
// The font definition file is "fonts/"+fn+".fnt" and the texture is "fonts/"+fn+".tga"
|
||||
|
@ -54,7 +54,7 @@
|
||||
# define ZLIB_DLL
|
||||
# include <zlib.h>
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# if MSC_VERSION
|
||||
# ifdef NDEBUG
|
||||
# pragma comment(lib, "zlib1.lib")
|
||||
# else
|
||||
@ -884,16 +884,8 @@ int inf_free_ctx(uintptr_t _ctx)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
enum ZFileFlags
|
||||
{
|
||||
// the ZFile has been successfully zip_map-ped.
|
||||
// used to make sure the archive's mmap refcount remains balanced,
|
||||
// i.e. no one double-frees the mapping.
|
||||
ZF_HAS_MAPPING = 0x4000
|
||||
};
|
||||
|
||||
// marker for ZFile struct, to make sure it's valid
|
||||
#ifdef PARANOIA
|
||||
#if CONFIG_PARANOIA
|
||||
static const u32 ZFILE_MAGIC = FOURCC('Z','F','I','L');
|
||||
#endif
|
||||
|
||||
@ -909,10 +901,6 @@ static int zfile_validate(uint line, ZFile* zf)
|
||||
msg = "ZFile* parameter = 0";
|
||||
err = ERR_INVALID_PARAM;
|
||||
}
|
||||
#ifdef PARANOIA
|
||||
else if(zf->magic != ZFILE_MAGIC)
|
||||
msg = "ZFile corrupted (magic field incorrect)";
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
// else if(!h_user_data(zf->ha, H_ZArchive))
|
||||
// msg = "invalid archive handle";
|
||||
@ -934,7 +922,7 @@ static int zfile_validate(uint line, ZFile* zf)
|
||||
return err;
|
||||
}
|
||||
|
||||
#define CHECK_ZFILE(f) CHECK_ERR(zfile_validate(__LINE__, f))
|
||||
#define CHECK_ZFILE(f) RETURN_ERR(zfile_validate(__LINE__, f))
|
||||
|
||||
|
||||
// convenience function, allows implementation change in ZFile.
|
||||
@ -969,7 +957,7 @@ int zip_stat(Handle ha, const char* fn, struct stat* s)
|
||||
|
||||
// open file, and fill *zf with information about it.
|
||||
// return < 0 on error (output param zeroed).
|
||||
int zip_open(const Handle ha, const char* fn, ZFile* zf)
|
||||
int zip_open(const Handle ha, const char* fn, int flags, ZFile* zf)
|
||||
{
|
||||
// zero output param in case we fail below.
|
||||
memset(zf, 0, sizeof(ZFile));
|
||||
@ -980,20 +968,16 @@ int zip_open(const Handle ha, const char* fn, ZFile* zf)
|
||||
ZLoc loc;
|
||||
// don't want ZFile to contain a ZEnt struct -
|
||||
// its ucsize member must be 'loose' for compatibility with File.
|
||||
// => need to copy ZEnt fields into ZFile.
|
||||
CHECK_ERR(lookup_get_file_info(li, fn, &loc));
|
||||
|
||||
#ifdef PARANOIA
|
||||
zf->magic = ZFILE_MAGIC;
|
||||
#endif
|
||||
|
||||
zf->ucsize = loc.ucsize;
|
||||
zf->ofs = loc.ofs;
|
||||
zf->csize = loc.csize;
|
||||
|
||||
zf->ha = ha;
|
||||
zf->inf_ctx = inf_init_ctx(zfile_compressed(zf));
|
||||
// => need to copy ZLoc fields into ZFile.
|
||||
RETURN_ERR(lookup_get_file_info(li, fn, &loc));
|
||||
|
||||
zf->flags = flags;
|
||||
zf->ucsize = loc.ucsize;
|
||||
zf->ofs = loc.ofs;
|
||||
zf->csize = loc.csize;
|
||||
zf->ha = ha;
|
||||
zf->inf_ctx = inf_init_ctx(zfile_compressed(zf));
|
||||
zf->is_mapped = 0;
|
||||
CHECK_ZFILE(zf);
|
||||
|
||||
return 0;
|
||||
@ -1029,13 +1013,13 @@ static const size_t CHUNK_SIZE = 16*KiB;
|
||||
|
||||
// begin transferring <size> bytes, starting at <ofs>. get result
|
||||
// with zip_wait_io; when no longer needed, free via zip_discard_io.
|
||||
int zip_start_io(ZFile* zf, off_t user_ofs, size_t max_output_size, void* user_buf, ZipIO* io)
|
||||
int zip_start_io(ZFile* zf, off_t user_ofs, size_t max_output_size, void* user_buf, ZipIo* io)
|
||||
{
|
||||
// not needed, since ZFile tells us the last read offset in the file.
|
||||
UNUSED(user_ofs);
|
||||
UNUSED2(user_ofs);
|
||||
|
||||
// zero output param in case we fail below.
|
||||
memset(io, 0, sizeof(ZipIO));
|
||||
memset(io, 0, sizeof(ZipIo));
|
||||
|
||||
CHECK_ZFILE(zf);
|
||||
H_DEREF(zf->ha, ZArchive, za);
|
||||
@ -1089,7 +1073,7 @@ int zip_start_io(ZFile* zf, off_t user_ofs, size_t max_output_size, void* user_b
|
||||
|
||||
// indicates if the IO referenced by <io> has completed.
|
||||
// return value: 0 if pending, 1 if complete, < 0 on error.
|
||||
int zip_io_complete(ZipIO* io)
|
||||
int zip_io_complete(ZipIo* io)
|
||||
{
|
||||
if(io->already_inflated)
|
||||
return 1;
|
||||
@ -1099,7 +1083,7 @@ int zip_io_complete(ZipIO* io)
|
||||
|
||||
// wait until the transfer <io> completes, and return its buffer.
|
||||
// output parameters are zeroed on error.
|
||||
int zip_wait_io(ZipIO* io, void*& buf, size_t& size)
|
||||
int zip_wait_io(ZipIo* io, void*& buf, size_t& size)
|
||||
{
|
||||
buf = io->user_buf;
|
||||
size = io->max_output_size;
|
||||
@ -1113,9 +1097,11 @@ int zip_wait_io(ZipIO* io, void*& buf, size_t& size)
|
||||
if(io->inf_ctx)
|
||||
{
|
||||
inf_set_dest(io->inf_ctx, buf, size);
|
||||
ssize_t bytes_inflated = inf_inflate(io->inf_ctx, raw_buf, raw_size, true);
|
||||
// true: we allocated the compressed data input buffer, and
|
||||
// want it freed when it's consumed.
|
||||
// we allocated the compressed data input buffer and
|
||||
// want it freed when it's consumed.
|
||||
const bool want_input_buf_freed = true;
|
||||
ssize_t bytes_inflated = inf_inflate(io->inf_ctx, raw_buf, raw_size, want_input_buf_freed);
|
||||
CHECK_ERR(bytes_inflated);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1128,7 +1114,7 @@ int zip_wait_io(ZipIO* io, void*& buf, size_t& size)
|
||||
|
||||
|
||||
// finished with transfer <io> - free its buffer (returned by zip_wait_io)
|
||||
int zip_discard_io(ZipIO* io)
|
||||
int zip_discard_io(ZipIo* io)
|
||||
{
|
||||
if(io->already_inflated)
|
||||
return 0;
|
||||
@ -1190,7 +1176,7 @@ ssize_t zip_read(ZFile* zf, off_t ofs, size_t size, void* p, FileIOCB cb, uintpt
|
||||
{
|
||||
CHECK_ZFILE(zf);
|
||||
|
||||
const bool compressed = zfile_compressed(zf);
|
||||
//const bool compressed = zfile_compressed(zf);
|
||||
|
||||
H_DEREF(zf->ha, ZArchive, za);
|
||||
|
||||
@ -1286,7 +1272,7 @@ int zip_map(ZFile* zf, void*& p, size_t& size)
|
||||
p = (char*)archive_p + zf->ofs;
|
||||
size = zf->ucsize;
|
||||
|
||||
zf->flags |= ZF_HAS_MAPPING;
|
||||
zf->is_mapped = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1302,9 +1288,9 @@ int zip_unmap(ZFile* zf)
|
||||
|
||||
// make sure archive mapping refcount remains balanced:
|
||||
// don't allow multiple|"false" unmaps.
|
||||
if(!(zf->flags & ZF_HAS_MAPPING))
|
||||
if(!zf->is_mapped)
|
||||
return -1;
|
||||
zf->flags &= ~ZF_HAS_MAPPING;
|
||||
zf->is_mapped = 0;
|
||||
|
||||
H_DEREF(zf->ha, ZArchive, za);
|
||||
return file_unmap(&za->f);
|
||||
|
@ -49,16 +49,11 @@ extern int zip_enum(const Handle ha, const FileCB cb, const uintptr_t user);
|
||||
|
||||
struct ZFile
|
||||
{
|
||||
#ifdef PARANOIA
|
||||
u32 magic;
|
||||
#endif
|
||||
|
||||
// keep offset of flags and size members in sync with struct File!
|
||||
// it is accessed by VFS and must be the same for both (union).
|
||||
// dirty, but necessary because VFile is pushing the HDATA size limit.
|
||||
uint flags;
|
||||
size_t ucsize;
|
||||
// size of logical file
|
||||
size_t ucsize; // uncompressed size
|
||||
|
||||
off_t ofs; // in archive
|
||||
off_t csize;
|
||||
@ -66,6 +61,11 @@ struct ZFile
|
||||
|
||||
Handle ha;
|
||||
uintptr_t inf_ctx;
|
||||
|
||||
// this ZFile has been successfully zip_map-ped, i.e. reference
|
||||
// count of the archive's mapping has been increased.
|
||||
// we need to undo that when closing it.
|
||||
uint is_mapped : 1;
|
||||
};
|
||||
|
||||
// get file status (size, mtime). output param is zeroed on error.
|
||||
@ -73,7 +73,7 @@ extern int zip_stat(Handle ha, const char* fn, struct stat* s);
|
||||
|
||||
// open file, and fill *zf with information about it.
|
||||
// return < 0 on error (output param zeroed).
|
||||
extern int zip_open(Handle ha, const char* fn, ZFile* zf);
|
||||
extern int zip_open(Handle ha, const char* fn, int flags, ZFile* zf);
|
||||
|
||||
// close file.
|
||||
extern int zip_close(ZFile* zf);
|
||||
@ -83,9 +83,9 @@ extern int zip_close(ZFile* zf);
|
||||
// asynchronous read
|
||||
//
|
||||
|
||||
struct ZipIO
|
||||
struct ZipIo
|
||||
{
|
||||
FileIO io;
|
||||
FileIo io;
|
||||
|
||||
uintptr_t inf_ctx;
|
||||
|
||||
@ -97,18 +97,18 @@ struct ZipIO
|
||||
|
||||
// begin transferring <size> bytes, starting at <ofs>. get result
|
||||
// with zip_wait_io; when no longer needed, free via zip_discard_io.
|
||||
extern int zip_start_io(ZFile* zf, off_t ofs, size_t size, void* buf, ZipIO* io);
|
||||
extern int zip_start_io(ZFile* zf, off_t ofs, size_t size, void* buf, ZipIo* io);
|
||||
|
||||
// indicates if the IO referenced by <io> has completed.
|
||||
// return value: 0 if pending, 1 if complete, < 0 on error.
|
||||
extern int zip_io_complete(ZipIO* io);
|
||||
extern int zip_io_complete(ZipIo* io);
|
||||
|
||||
// wait until the transfer <io> completes, and return its buffer.
|
||||
// output parameters are zeroed on error.
|
||||
extern int zip_wait_io(ZipIO* io, void*& p, size_t& size);
|
||||
extern int zip_wait_io(ZipIo* io, void*& p, size_t& size);
|
||||
|
||||
// finished with transfer <io> - free its buffer (returned by zip_wait_io)
|
||||
extern int zip_discard_io(ZipIO* io);
|
||||
extern int zip_discard_io(ZipIo* io);
|
||||
|
||||
|
||||
//
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#define SDL_BUTTON_INDEX_COUNT 5
|
||||
|
||||
#if defined(_WIN32) && !defined(NO_WSDL)
|
||||
#if OS_WIN && !defined(NO_WSDL)
|
||||
# include "sysdep/win/wsdl.h"
|
||||
|
||||
// The SDL_BUTTON_* enum is zero-based and in the range [0..4] in wsdl.h
|
||||
|
@ -78,7 +78,7 @@
|
||||
|
||||
// skip the functions on VC2005 (already provided there), but not our
|
||||
// self-test and the t* defines (needed for test).
|
||||
#if _MSC_VER < 1400
|
||||
#if MSC_VERSION < 1400
|
||||
|
||||
|
||||
// return length [in characters] of a string, not including the trailing
|
||||
@ -200,7 +200,7 @@ int tcat_s(tchar* dst, size_t max_dst_chars, const tchar* src)
|
||||
return tncat_s(dst, max_dst_chars, src, SIZE_MAX);
|
||||
}
|
||||
|
||||
#endif // #if _MSC_VER < 1400
|
||||
#endif // #if MSC_VERSION < 1400
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -4,10 +4,10 @@
|
||||
#include "posix_types.h" // size_t
|
||||
|
||||
// these are already shipped with VC2005
|
||||
#if _MSC_VER < 1400
|
||||
#if MSC_VERSION < 1400
|
||||
|
||||
// Conflicts with glibc definitions
|
||||
#ifndef OS_UNIX
|
||||
#if !OS_UNIX
|
||||
// return length [in characters] of a string, not including the trailing
|
||||
// null character. to protect against access violations, only the
|
||||
// first <max_len> characters are examined; if the null character is
|
||||
@ -53,6 +53,6 @@ extern int strcat_s(char* dst, size_t max_dst_chars, const char* src);
|
||||
extern int wcscat_s(wchar_t* dst, size_t max_dst_chars, const wchar_t* src);
|
||||
|
||||
|
||||
#endif // #if _MSC_VER < 1400
|
||||
#endif // #if MSC_VERSION < 1400
|
||||
|
||||
#endif // #ifndef STRINGS_S_H__
|
||||
|
@ -31,6 +31,10 @@ extern void get_cpu_info(void);
|
||||
// <new_value> and return true.
|
||||
extern bool CAS_(uintptr_t* location, uintptr_t expected, uintptr_t new_value);
|
||||
|
||||
// this is often used for pointers, so the macro coerces parameters to
|
||||
// uinptr_t. invalid usage unfortunately also goes through without warnings.
|
||||
// to catch cases where the caller has passed <expected> as <location> or
|
||||
// similar mishaps, the implementation verifies <location> is a valid pointer.
|
||||
#define CAS(l,o,n) CAS_((uintptr_t*)l, (uintptr_t)o, (uintptr_t)n)
|
||||
|
||||
extern void atomic_add(intptr_t* location, intptr_t increment);
|
||||
@ -40,6 +44,19 @@ extern void mfence();
|
||||
|
||||
extern void serialize();
|
||||
|
||||
// Win32 CONTEXT field abstraction
|
||||
// (there's no harm also defining this for other platforms)
|
||||
#if CPU_AMD64
|
||||
# define PC_ Rip
|
||||
# define FP_ Rbp
|
||||
# define SP_ Rsp
|
||||
#elif CPU_IA32
|
||||
# define PC_ Eip
|
||||
# define FP_ Ebp
|
||||
# define SP_ Esp
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "timer.h"
|
||||
|
||||
// HACK (see call to wtime_reset_impl)
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
#include "win/wtime.h"
|
||||
#endif
|
||||
|
||||
@ -35,10 +35,10 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef __GNUC__
|
||||
#if HAVE_ASM
|
||||
|
||||
// replace pathetic MS libc implementation
|
||||
#ifdef _WIN32
|
||||
// replace pathetic MS libc implementation.
|
||||
#if OS_WIN
|
||||
double _ceil(double f)
|
||||
{
|
||||
double r;
|
||||
@ -52,7 +52,7 @@ __asm
|
||||
fstp [r]
|
||||
}
|
||||
|
||||
UNUSED(f);
|
||||
UNUSED2(f);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -94,8 +94,8 @@ __asm
|
||||
pop eax
|
||||
}
|
||||
|
||||
UNUSED(new_cw);
|
||||
UNUSED(mask);
|
||||
UNUSED2(new_cw);
|
||||
UNUSED2(mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -537,12 +537,12 @@ void ia32_get_cpu_info()
|
||||
|
||||
measure_cpu_freq();
|
||||
|
||||
// HACK: if _WIN32, the HRT makes its final implementation choice
|
||||
// HACK: on Windows, the HRT makes its final implementation choice
|
||||
// in the first calibrate call where cpu info is available.
|
||||
// call wtime_reset_impl here to have that happen now,
|
||||
// so app code isn't surprised by a timer change, although the HRT
|
||||
// does try to keep the timer continuous.
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
wtime_reset_impl();
|
||||
#endif
|
||||
}
|
||||
@ -575,7 +575,7 @@ bool __cdecl CAS_(uintptr_t* location, uintptr_t expected, uintptr_t new_value)
|
||||
{
|
||||
// try to see if caller isn't passing in an address
|
||||
// (CAS's arguments are silently casted)
|
||||
ASSERT(location >= (uintptr_t*)0x10000);
|
||||
ASSERT(!debug_is_pointer_bogus(location));
|
||||
|
||||
bool was_updated;
|
||||
__asm
|
||||
@ -624,7 +624,7 @@ void serialize()
|
||||
__asm cpuid
|
||||
}
|
||||
|
||||
#else // #ifndef __GNUC__
|
||||
#else // i.e. #if !HAVE_ASM
|
||||
|
||||
bool CAS_(uintptr_t* location, uintptr_t expected, uintptr_t new_value)
|
||||
{
|
||||
@ -669,4 +669,4 @@ void serialize()
|
||||
__asm__ __volatile__ ("cpuid");
|
||||
}
|
||||
|
||||
#endif // #ifdef __GNUC__
|
||||
#endif // #if HAVE_ASM
|
||||
|
@ -18,8 +18,8 @@
|
||||
#ifndef IA32_H
|
||||
#define IA32_H
|
||||
|
||||
#if !(defined(__GNUC__) && defined(i386)) && !defined(_M_IX86)
|
||||
#error "including ia32.h without _M_IX86 (or both __GNUC__ and i386) defined"
|
||||
#if !CPU_IA32
|
||||
#error "including ia32.h without CPU_IA32=1
|
||||
#endif
|
||||
|
||||
#include "lib/types.h"
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <memory.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
|
||||
double round(double x)
|
||||
{
|
||||
@ -15,7 +15,7 @@ double round(double x)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_C99
|
||||
#if !HAVE_C99
|
||||
|
||||
float fminf(float a, float b)
|
||||
{
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#if OS_WIN
|
||||
# include "win/win.h"
|
||||
#elif defined(OS_UNIX)
|
||||
#elif OS_UNIX
|
||||
# include "unix/unix.h"
|
||||
#endif
|
||||
|
||||
@ -13,10 +13,20 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// compiling without exceptions (usually for performance reasons);
|
||||
// tell STL not to generate any.
|
||||
#if CONFIG_DISABLE_EXCEPTIONS
|
||||
# if OS_WIN
|
||||
# define _HAS_EXCEPTIONS 0
|
||||
# else
|
||||
# define STL_NO_EXCEPTIONS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// vsnprintf2: handles positional parameters and %lld.
|
||||
// already available on *nix, emulated on Win32.
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
extern int vsnprintf2(char* buffer, size_t count, const char* format, va_list argptr);
|
||||
#else
|
||||
#define vsnprintf2 vsnprintf
|
||||
@ -24,11 +34,22 @@ extern int vsnprintf2(char* buffer, size_t count, const char* format, va_list ar
|
||||
|
||||
// alloca: allocate on stack, automatically free, return 0 if out of mem.
|
||||
// already available on *nix, emulated on Win32.
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
#undef alloca // from malloc.h
|
||||
extern void* alloca(size_t size);
|
||||
#endif
|
||||
|
||||
// finite: return 0 iff the given double is infinite or NaN.
|
||||
#if OS_WIN
|
||||
# define finite _finite
|
||||
#else
|
||||
# define finite __finite
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// output
|
||||
//
|
||||
|
||||
enum DisplayErrorFlags
|
||||
{
|
||||
@ -74,11 +95,35 @@ extern void display_msg(const char* caption, const char* msg);
|
||||
extern void wdisplay_msg(const wchar_t* caption, const wchar_t* msg);
|
||||
|
||||
|
||||
//
|
||||
// clipboard
|
||||
//
|
||||
|
||||
extern int clipboard_set(const wchar_t* text);
|
||||
extern wchar_t* clipboard_get(void);
|
||||
extern int clipboard_free(wchar_t* copy);
|
||||
|
||||
|
||||
//
|
||||
// mouse cursor
|
||||
//
|
||||
|
||||
// creates a cursor from the given 32 bpp RGBA texture. hotspot (hx,hy) is
|
||||
// the offset from its upper-left corner to the position where mouse clicks
|
||||
// are registered.
|
||||
// the cursor must be cursor_free-ed when no longer needed.
|
||||
extern int cursor_create(int w, int h, void* img, int hx, int hy,
|
||||
void** cursor);
|
||||
|
||||
// replaces the current system cursor with the one indicated. need only be
|
||||
// called once per cursor; pass 0 to restore the default.
|
||||
extern int cursor_set(void* cursor);
|
||||
|
||||
// destroys the indicated cursor and frees its resources. if it is
|
||||
// currently the system cursor, the default cursor is restored first.
|
||||
extern int cursor_free(void* cursor);
|
||||
|
||||
|
||||
extern int get_executable_name(char* n_path, size_t buf_size);
|
||||
|
||||
// return filename of the module which contains address <addr>,
|
||||
@ -89,16 +134,16 @@ wchar_t* get_module_filename(void* addr, wchar_t* path);
|
||||
extern int pick_directory(char* n_path, size_t buf_size);
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
extern double round(double);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_C99
|
||||
#if !HAVE_C99
|
||||
extern float fminf(float a, float b);
|
||||
extern float fmaxf(float a, float b);
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#if !MSC_VERSION
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#endif
|
||||
@ -112,7 +157,7 @@ extern float fmaxf(float a, float b);
|
||||
// C++ linkage
|
||||
|
||||
// STL_HASH_MAP, STL_HASH_MULTIMAP, STL_HASH_SET
|
||||
#ifdef __GNUC__
|
||||
#if GCC_VERSION
|
||||
// GCC
|
||||
# include <ext/hash_map>
|
||||
# include <ext/hash_set> // Probably?
|
||||
@ -139,19 +184,19 @@ namespace __gnu_cxx
|
||||
#else // !__GNUC__
|
||||
# include <hash_map>
|
||||
# include <hash_set>
|
||||
# if defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
// VC7 or above
|
||||
# if MSC_VERSION >= 1300
|
||||
# define STL_HASH_MAP stdext::hash_map
|
||||
# define STL_HASH_MULTIMAP stdext::hash_multimap
|
||||
# define STL_HASH_SET stdext::hash_set
|
||||
# define STL_HASH_MULTISET stdext::hash_multiset
|
||||
# else
|
||||
// VC6 and anything else (most likely name)
|
||||
# else
|
||||
# define STL_HASH_MAP std::hash_map
|
||||
# define STL_HASH_MULTIMAP std::hash_multimap
|
||||
# define STL_HASH_SET std::hash_set
|
||||
# define STL_HASH_MULTISET std::hash_multiset
|
||||
# endif // defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
# endif // MSC_VERSION >= 1300
|
||||
#endif // !__GNUC__
|
||||
|
||||
#include "debug.h"
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "error_dialog.h"
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
@ -40,6 +41,7 @@ END
|
||||
IDD_DIALOG1 DIALOGEX 0, 0, 328, 260
|
||||
STYLE DS_SETFONT | DS_SETFOREGROUND | DS_FIXEDSYS | WS_MINIMIZEBOX |
|
||||
WS_MAXIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
|
||||
EXSTYLE WS_EX_TOPMOST | WS_EX_APPWINDOW
|
||||
CAPTION "Program Error"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
|
@ -271,7 +271,7 @@ extern "C" int vsnprintf2(TCHAR* buffer, size_t count, const TCHAR* format, va_l
|
||||
|
||||
if (chr == _T('I'))
|
||||
{
|
||||
debug_assert(! "MSVC-style \"%I64\" is not allowed!");
|
||||
debug_warn("MSVC-style \"%I64\" is not allowed!");
|
||||
}
|
||||
|
||||
if (is_lengthmod(chr))
|
||||
@ -363,7 +363,7 @@ finished_reading:
|
||||
if (s->length > 256)
|
||||
{
|
||||
if (s->length == 0x00006c6c)
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
newformat += "I64"; // MSVC compatibility
|
||||
#else
|
||||
newformat += "ll";
|
||||
@ -399,7 +399,7 @@ finished_reading:
|
||||
*/
|
||||
|
||||
// Because of those dangerous assumptions about varargs:
|
||||
#ifndef _M_IX86
|
||||
#if !CPU_IA32
|
||||
#error SLIGHTLY FATAL ERROR: Only x86 is supported!
|
||||
#endif
|
||||
|
||||
@ -420,7 +420,7 @@ finished_reading:
|
||||
{
|
||||
if (varsizes[i] <= 0)
|
||||
{
|
||||
debug_assert(! "Invalid variable type somewhere - make sure all variable things are positional and defined");
|
||||
debug_warn("Invalid variable type somewhere - make sure all variable things are positional and defined");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -442,7 +442,7 @@ finished_reading:
|
||||
FormatVariable* s = static_cast<FormatVariable*>(*it);
|
||||
if (s->position <= 0)
|
||||
{
|
||||
debug_assert(! "Invalid use of positional elements - make sure all variable things are positional and defined");
|
||||
debug_warn("Invalid use of positional elements - make sure all variable things are positional and defined");
|
||||
return -1;
|
||||
}
|
||||
newstack += std::string( stackitems[s->position-1].first, stackitems[s->position-1].second );
|
||||
|
@ -642,7 +642,7 @@ int aio_cancel(int fd, struct aiocb* cb)
|
||||
{
|
||||
// Win32 limitation: can't cancel single transfers -
|
||||
// all pending reads on this file are cancelled.
|
||||
UNUSED(cb);
|
||||
UNUSED2(cb);
|
||||
|
||||
const HANDLE h = aio_h_get(fd);
|
||||
if(h == INVALID_HANDLE_VALUE)
|
||||
@ -671,7 +671,7 @@ int aio_write(struct aiocb* cb)
|
||||
|
||||
int lio_listio(int mode, struct aiocb* const cbs[], int n, struct sigevent* se)
|
||||
{
|
||||
UNUSED(se);
|
||||
UNUSED2(se);
|
||||
|
||||
int err = 0;
|
||||
|
||||
|
@ -217,7 +217,7 @@ static uintptr_t get_target_pc()
|
||||
if(ret == (DWORD)-1)
|
||||
{
|
||||
debug_warn("get_target_pc: SuspendThread failed");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
// note: we don't need to call more than once: this increments a DWORD
|
||||
// 'suspend count'; target is guaranteed to be suspended unless
|
||||
@ -236,15 +236,7 @@ static uintptr_t get_target_pc()
|
||||
CONTEXT context;
|
||||
context.ContextFlags = CONTEXT_CONTROL;
|
||||
if(GetThreadContext(hThread, &context))
|
||||
{
|
||||
#if defined(_M_AMD64)
|
||||
pc = context.Rip;
|
||||
#elif defined(_M_IX86)
|
||||
pc = context.Eip;
|
||||
#else
|
||||
# error "port CONTEXT"
|
||||
#endif
|
||||
}
|
||||
pc = context.PC_;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
|
||||
@ -259,9 +251,9 @@ static uintptr_t get_target_pc()
|
||||
static pthread_t thread;
|
||||
static sem_t exit_flag;
|
||||
|
||||
static void* prof_thread_func(void* data)
|
||||
static void* prof_thread_func(void* UNUSED(data))
|
||||
{
|
||||
UNUSED(data);
|
||||
debug_set_thread_name("profiler");
|
||||
|
||||
const long _1e6 = 1000000;
|
||||
const long _1e9 = 1000000000;
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "byte_order.h" // FOURCC
|
||||
|
||||
// optional: enables translation of the "unhandled exception" dialog.
|
||||
#ifdef I18N
|
||||
#if HAVE_I18N
|
||||
#include "ps/i18n.h"
|
||||
#endif
|
||||
|
||||
@ -68,7 +68,7 @@ static bool is_locked()
|
||||
// program will terminate soon after. fixing this is hard and senseless.
|
||||
static const wchar_t* translate(const wchar_t* text)
|
||||
{
|
||||
#ifdef HAVE_I18N
|
||||
#if HAVE_I18N
|
||||
// make sure i18n system is (already|still) initialized.
|
||||
if(g_CurrentLocale)
|
||||
{
|
||||
@ -142,6 +142,37 @@ void debug_wprintf(const wchar_t* fmt, ...)
|
||||
}
|
||||
|
||||
|
||||
// inform the debugger of the current thread's description, which it then
|
||||
// displays instead of just the thread handle.
|
||||
void wdbg_set_thread_name(const char* name)
|
||||
{
|
||||
// we pass information to the debugger via a special exception it
|
||||
// swallows. if not running under one, bail now to avoid
|
||||
// "first chance exception" warnings.
|
||||
if(!IsDebuggerPresent())
|
||||
return;
|
||||
|
||||
// presented by Jay Bazuzi (from the VC debugger team) at TechEd 1999.
|
||||
const struct ThreadNameInfo
|
||||
{
|
||||
DWORD type;
|
||||
const char* name;
|
||||
DWORD thread_id; // any valid ID or -1 for current thread
|
||||
DWORD flags;
|
||||
}
|
||||
info = { 0x1000, name, (DWORD)-1, 0 };
|
||||
__try
|
||||
{
|
||||
RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info);
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
// if we get here, apparently this hack is not longer supported.
|
||||
debug_warn("TODO: find alternative thread name implementation");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// debug memory allocator
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -169,41 +200,53 @@ void debug_heap_check()
|
||||
// if not called, the default is DEBUG_HEAP_NONE, i.e. do nothing.
|
||||
void debug_heap_enable(DebugHeapChecks what)
|
||||
{
|
||||
#ifdef HAVE_VC_DEBUG_ALLOC
|
||||
// note: if MMGR is enabled, crtdbg.h will not have been included.
|
||||
// in that case, we do nothing here - this interface is too basic to
|
||||
// control mmgr; use its API instead.
|
||||
#if !CONFIG_USE_MMGR && HAVE_VC_DEBUG_ALLOC
|
||||
uint flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
||||
switch(what)
|
||||
{
|
||||
case DEBUG_HEAP_NONE:
|
||||
flags = 0;
|
||||
// note: do not set flags to zero because we might trash some
|
||||
// important flag value.
|
||||
flags &= ~(_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_DELAY_FREE_MEM_DF |
|
||||
_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
|
||||
break;
|
||||
case DEBUG_HEAP_NORMAL:
|
||||
flags |= _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF;
|
||||
flags |= _CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF;
|
||||
break;
|
||||
case DEBUG_HEAP_ALL:
|
||||
flags |= _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_DELAY_FREE_MEM_DF |
|
||||
_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF;
|
||||
flags |= (_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_DELAY_FREE_MEM_DF |
|
||||
_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
|
||||
break;
|
||||
default:
|
||||
debug_assert("debug_heap_enable: invalid what");
|
||||
}
|
||||
_CrtSetDbgFlag(flags);
|
||||
#else
|
||||
UNUSED2(what);
|
||||
#endif // HAVE_DEBUGALLOC
|
||||
}
|
||||
|
||||
|
||||
// return 1 if the pointer appears to be totally bogus, otherwise 0.
|
||||
// this check is not authoritative in that the pointer may in truth
|
||||
// be invalid regardless of the return value here, but can be used
|
||||
// to filter out obviously wrong values in a portable manner.
|
||||
int debug_is_bogus_pointer(const void* p)
|
||||
// this check is not authoritative (the pointer may be "valid" but incorrect)
|
||||
// but can be used to filter out obviously wrong values in a portable manner.
|
||||
int debug_is_pointer_bogus(const void* p)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
#if CPU_IA32
|
||||
if(p < (void*)0x10000)
|
||||
return true;
|
||||
if(p >= (void*)(uintptr_t)0x80000000)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
// note: we don't check alignment because nothing can be assumed about a
|
||||
// pointer to the middle of a string and we mustn't reject valid pointers.
|
||||
// nor do we bother checking the address against known stack/heap areas
|
||||
// because that doesn't cover everything (e.g. DLLs, VirtualAlloc, etc.).
|
||||
|
||||
return IsBadReadPtr(p, 1) != 0;
|
||||
}
|
||||
|
||||
@ -225,6 +268,8 @@ struct WhileSuspendedParam
|
||||
|
||||
static void* while_suspended_thread_func(void* user_arg)
|
||||
{
|
||||
debug_set_thread_name("suspender");
|
||||
|
||||
DWORD err;
|
||||
WhileSuspendedParam* param = (WhileSuspendedParam*)user_arg;
|
||||
|
||||
@ -269,8 +314,7 @@ static int call_while_suspended(WhileSuspendedFunc func, void* user_arg)
|
||||
WhileSuspendedParam param = { hThread, func, user_arg };
|
||||
|
||||
pthread_t thread;
|
||||
err = pthread_create(&thread, 0, while_suspended_thread_func, ¶m);
|
||||
debug_assert(err == 0);
|
||||
WARN_ERR(pthread_create(&thread, 0, while_suspended_thread_func, ¶m));
|
||||
|
||||
void* ret;
|
||||
err = pthread_join(thread, &ret);
|
||||
@ -317,7 +361,7 @@ static const uint MAX_BREAKPOINTS = 4;
|
||||
|
||||
// remove all breakpoints enabled by debug_set_break from <context>.
|
||||
// called while target is suspended.
|
||||
static int brk_disable_all_in_ctx(BreakInfo* bi, CONTEXT* context)
|
||||
static int brk_disable_all_in_ctx(BreakInfo* UNUSED(bi), CONTEXT* context)
|
||||
{
|
||||
context->Dr7 &= ~brk_all_local_enables;
|
||||
return 0;
|
||||
@ -405,20 +449,20 @@ static int brk_do_request(HANDLE hThread, void* arg)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#if defined(_M_IX86)
|
||||
#if CPU_IA32
|
||||
if(bi->want_all_disabled)
|
||||
ret = brk_disable_all_in_ctx(bi, &context);
|
||||
else
|
||||
ret = brk_enable_in_ctx (bi, &context);
|
||||
#else
|
||||
#error "port"
|
||||
#endif
|
||||
|
||||
if(!SetThreadContext(hThread, &context))
|
||||
{
|
||||
debug_warn("brk_do_request: SetThreadContext failed");
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
#error "port"
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
@ -781,7 +825,7 @@ struct XInfo
|
||||
// (compiler-specific).
|
||||
static bool isCppException(const EXCEPTION_RECORD* er)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
// note: representation of 'msc' isn't specified, so use FOURCC
|
||||
if(er->ExceptionCode != FOURCC(0xe0, 'm','s','c'))
|
||||
return false;
|
||||
@ -1026,7 +1070,7 @@ LONG WINAPI wdbg_exception_filter(EXCEPTION_POINTERS* ep)
|
||||
swprintf(fmt, ARRAY_SIZE(fmt), L"%%%ds (%%%dh[^:]:%%d)", DBG_SYMBOL_LEN, DBG_FILE_LEN);
|
||||
// bake in the string limits (future-proof)
|
||||
(void)swscanf(locus, fmt, func_name, file, &line);
|
||||
// don't care if all 3 fields were filled (they default to "?")
|
||||
// don't care whether all 3 fields were filled (they default to "?")
|
||||
|
||||
wchar_t buf[500];
|
||||
const wchar_t* msg_fmt =
|
||||
|
@ -18,18 +18,19 @@
|
||||
#ifndef WDBG_H__
|
||||
#define WDBG_H__
|
||||
|
||||
#include "lib/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
# define debug_break() __asm { int 3 }
|
||||
#else
|
||||
# error "port this or define to implementation function"
|
||||
#endif
|
||||
|
||||
// internal use only:
|
||||
extern void wdbg_set_thread_name(const char* name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -40,7 +40,7 @@
|
||||
#define PERFORM_SELF_TEST 0
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
#pragma comment(lib, "oleaut32.lib") // VariantChangeType
|
||||
#endif
|
||||
@ -269,17 +269,8 @@ int debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int*
|
||||
// but WinXP SP2 and above require it be suspended.
|
||||
|
||||
// copy from CONTEXT to STACKFRAME64
|
||||
#if defined(_M_AMD64)
|
||||
# define PC_ Rip
|
||||
# define FP_ Rbp
|
||||
# define SP_ Rsp
|
||||
#elif defined(_M_IX86)
|
||||
# define PC_ Eip
|
||||
# define FP_ Ebp
|
||||
# define SP_ Esp
|
||||
#endif
|
||||
|
||||
#ifdef _M_IX86
|
||||
#if CPU_IA32
|
||||
|
||||
// optimized for size.
|
||||
// this is the (so far) only case where __declspec(naked) is absolutely
|
||||
@ -288,6 +279,8 @@ int debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int*
|
||||
// on us returning their correct values.
|
||||
static __declspec(naked) void get_current_context(void* pcontext)
|
||||
{
|
||||
// squelch W4 unused paramter warning (it's accessed from asm)
|
||||
UNUSED2(pcontext);
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
@ -357,7 +350,7 @@ rep stosd
|
||||
}
|
||||
}
|
||||
|
||||
#else // #ifdef _M_IX86
|
||||
#else // #if CPU_IA32
|
||||
|
||||
static void get_current_context(CONTEXT* pcontext)
|
||||
{
|
||||
@ -810,7 +803,7 @@ static void seq_determine_formatting(size_t el_size, size_t el_count,
|
||||
static int dump_sequence(DebugIterator el_iterator, void* internal,
|
||||
size_t el_count, DWORD el_type_id, size_t el_size, DumpState state)
|
||||
{
|
||||
const u8* el_p;
|
||||
const u8* el_p = 0; // avoid "uninitialized" warning
|
||||
|
||||
// special case: display as a string if the sequence looks to be text.
|
||||
// do this only if container isn't empty because the otherwise the
|
||||
@ -891,7 +884,7 @@ static int dump_array(const u8* p,
|
||||
|
||||
|
||||
|
||||
static int determine_symbol_address(DWORD id, DWORD type_id, const u8** pp)
|
||||
static int determine_symbol_address(DWORD id, DWORD UNUSED(type_id), const u8** pp)
|
||||
{
|
||||
const STACKFRAME64* sf = current_stackframe64;
|
||||
|
||||
@ -1030,6 +1023,11 @@ static int dump_sym_base_type(DWORD type_id, const u8* p, DumpState state)
|
||||
return WDBG_TYPE_INFO_UNAVAILABLE;
|
||||
const size_t size = (size_t)size_;
|
||||
|
||||
// single out() call. note: we pass a single u64 for all sizes,
|
||||
// which will only work on little-endian systems.
|
||||
// must be declared before goto to avoid W4 warning.
|
||||
const wchar_t* fmt = L"";
|
||||
|
||||
u64 data = movzx_64le(p, size);
|
||||
// if value is 0xCC..CC (uninitialized mem), we display as hex.
|
||||
// the output would otherwise be garbage; this makes it obvious.
|
||||
@ -1042,10 +1040,6 @@ static int dump_sym_base_type(DWORD type_id, const u8* p, DumpState state)
|
||||
goto display_as_hex;
|
||||
}
|
||||
|
||||
// single out() call. note: we pass a single u64 for all sizes,
|
||||
// which will only work on little-endian systems.
|
||||
const wchar_t* fmt = L"";
|
||||
|
||||
switch(base_type)
|
||||
{
|
||||
// boolean
|
||||
@ -1171,12 +1165,16 @@ static int dump_sym_base_class(DWORD type_id, const u8* p, DumpState state)
|
||||
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_TYPEID, &base_class_type_id))
|
||||
return WDBG_TYPE_INFO_UNAVAILABLE;
|
||||
|
||||
// this is a virtual base class. we can't display those because it'd
|
||||
// require reading the VTbl, which is difficult given lack of documentation
|
||||
// and just not worth it.
|
||||
DWORD vptr_ofs;
|
||||
if(SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_VIRTUALBASEPOINTEROFFSET, &vptr_ofs))
|
||||
return WDBG_UNSUPPORTED;
|
||||
|
||||
return dump_sym(base_class_type_id, p, state);
|
||||
|
||||
|
||||
// unsupported: virtual base classes would require reading the VTbl,
|
||||
// which is difficult given lack of documentation and not worth it.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1213,7 +1211,7 @@ static int dump_sym_data(DWORD id, const u8* p, DumpState state)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static int dump_sym_enum(DWORD type_id, const u8* p, DumpState state)
|
||||
static int dump_sym_enum(DWORD type_id, const u8* p, DumpState UNUSED(state))
|
||||
{
|
||||
ULONG64 size_ = 0;
|
||||
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_LENGTH, &size_))
|
||||
@ -1271,7 +1269,8 @@ static int dump_sym_enum(DWORD type_id, const u8* p, DumpState state)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static int dump_sym_function(DWORD type_id, const u8* p, DumpState state)
|
||||
static int dump_sym_function(DWORD UNUSED(type_id), const u8* UNUSED(p),
|
||||
DumpState UNUSED(state))
|
||||
{
|
||||
return WDBG_SUPPRESS_OUTPUT;
|
||||
}
|
||||
@ -1279,7 +1278,7 @@ static int dump_sym_function(DWORD type_id, const u8* p, DumpState state)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static int dump_sym_function_type(DWORD type_id, const u8* p, DumpState state)
|
||||
static int dump_sym_function_type(DWORD UNUSED(type_id), const u8* p, DumpState UNUSED(state))
|
||||
{
|
||||
// this symbol gives class parent, return type, and parameter count.
|
||||
// unfortunately the one thing we care about, its name,
|
||||
@ -1342,7 +1341,7 @@ static int dump_sym_pointer(DWORD type_id, const u8* p, DumpState state)
|
||||
|
||||
// bail if it's obvious the pointer is bogus
|
||||
// (=> can't display what it's pointing to)
|
||||
if(debug_is_bogus_pointer(p))
|
||||
if(debug_is_pointer_bogus(p))
|
||||
return 0;
|
||||
|
||||
// avoid duplicates and circular references
|
||||
@ -1527,8 +1526,8 @@ not_handle:
|
||||
}
|
||||
|
||||
|
||||
static int udt_dump_suppressed(const wchar_t* type_name, const u8* p, size_t size,
|
||||
DumpState state, ULONG num_children, const DWORD* children)
|
||||
static int udt_dump_suppressed(const wchar_t* type_name, const u8* UNUSED(p), size_t UNUSED(size),
|
||||
DumpState state, ULONG UNUSED(num_children), const DWORD* UNUSED(children))
|
||||
{
|
||||
if(!udt_should_suppress(type_name))
|
||||
return 1;
|
||||
@ -1695,7 +1694,7 @@ done:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
static int dump_sym_vtable(DWORD type_id, const u8* p, DumpState state)
|
||||
static int dump_sym_vtable(DWORD UNUSED(type_id), const u8* UNUSED(p), DumpState UNUSED(state))
|
||||
{
|
||||
// unsupported (vtable internals are undocumented; too much work).
|
||||
return WDBG_SUPPRESS_OUTPUT;
|
||||
@ -1705,7 +1704,7 @@ static int dump_sym_vtable(DWORD type_id, const u8* p, DumpState state)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
static int dump_sym_unknown(DWORD type_id, const u8* p, DumpState state)
|
||||
static int dump_sym_unknown(DWORD type_id, const u8* UNUSED(p), DumpState UNUSED(state))
|
||||
{
|
||||
// redundant (already done in dump_sym), but this is rare.
|
||||
DWORD type_tag;
|
||||
@ -1770,7 +1769,7 @@ static int dump_sym(DWORD type_id, const u8* p, DumpState state)
|
||||
|
||||
// output the symbol's name and value via dump_sym*.
|
||||
// called from dump_frame_cb for each local symbol; lock is held.
|
||||
static BOOL CALLBACK dump_sym_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
|
||||
static BOOL CALLBACK dump_sym_cb(SYMBOL_INFO* sym, ULONG UNUSED(size), void* UNUSED(ctx))
|
||||
{
|
||||
out_latch_pos(); // see decl
|
||||
mod_base = sym->ModBase;
|
||||
@ -1813,9 +1812,8 @@ struct IMAGEHLP_STACK_FRAME2 : public IMAGEHLP_STACK_FRAME
|
||||
};
|
||||
|
||||
// called by walk_stack for each stack frame
|
||||
static int dump_frame_cb(const STACKFRAME64* sf, void* user_arg)
|
||||
static int dump_frame_cb(const STACKFRAME64* sf, void* UNUSED(user_arg))
|
||||
{
|
||||
UNUSED(user_arg);
|
||||
current_stackframe64 = sf;
|
||||
void* func = (void*)sf->AddrPC.Offset;
|
||||
|
||||
@ -2082,13 +2080,13 @@ static void test_stl()
|
||||
std::vector<double> v_double_empty;
|
||||
std::queue<double> q_double_empty;
|
||||
std::stack<double> st_double_empty;
|
||||
#ifdef HAVE_STL_HASH
|
||||
#if HAVE_STL_HASH
|
||||
STL_HASH_MAP<double,double> hm_double_empty;
|
||||
STL_HASH_MULTIMAP<double,std::wstring> hmm_double_empty;
|
||||
STL_HASH_SET<double> hs_double_empty;
|
||||
STL_HASH_MULTISET<double> hms_double_empty;
|
||||
#endif
|
||||
#ifdef HAVE_STL_SLIST
|
||||
#if HAVE_STL_SLIST
|
||||
STL_SLIST<double> sl_double_empty;
|
||||
#endif
|
||||
std::string str_empty;
|
||||
@ -2106,13 +2104,13 @@ static void test_stl()
|
||||
std::vector<double> v_double_uninit;
|
||||
std::queue<double> q_double_uninit;
|
||||
std::stack<double> st_double_uninit;
|
||||
#ifdef HAVE_STL_HASH
|
||||
#if HAVE_STL_HASH
|
||||
STL_HASH_MAP<double,double> hm_double_uninit;
|
||||
STL_HASH_MULTIMAP<double,std::wstring> hmm_double_uninit;
|
||||
STL_HASH_SET<double> hs_double_uninit;
|
||||
STL_HASH_MULTISET<double> hms_double_uninit;
|
||||
#endif
|
||||
#ifdef HAVE_STL_SLIST
|
||||
#if HAVE_STL_SLIST
|
||||
STL_SLIST<double> sl_double_uninit;
|
||||
#endif
|
||||
std::string str_uninit;
|
||||
@ -2152,11 +2150,11 @@ static void test_addrs(int p_int, double p_double, char* p_pchar, uintptr_t p_ui
|
||||
|
||||
test_stl();
|
||||
|
||||
int uninit_int; UNUSED(uninit_int);
|
||||
float uninit_float; UNUSED(uninit_float);
|
||||
double uninit_double; UNUSED(uninit_double);
|
||||
bool uninit_bool; UNUSED(uninit_bool);
|
||||
HWND uninit_hwnd; UNUSED(uninit_hwnd);
|
||||
int uninit_int; UNUSED2(uninit_int);
|
||||
float uninit_float; UNUSED2(uninit_float);
|
||||
double uninit_double; UNUSED2(uninit_double);
|
||||
bool uninit_bool; UNUSED2(uninit_bool);
|
||||
HWND uninit_hwnd; UNUSED2(uninit_hwnd);
|
||||
}
|
||||
|
||||
|
||||
|
@ -255,14 +255,14 @@ FLoadedAtPreferredAddress(PIMAGE_NT_HEADERS pinh, HMODULE hmod) {
|
||||
|
||||
// Do the InterlockedExchange magic
|
||||
//
|
||||
#ifdef _M_IX86
|
||||
#if CPU_IA32
|
||||
|
||||
#undef InterlockedExchangePointer
|
||||
#define InterlockedExchangePointer(Target, Value) \
|
||||
(PVOID)(uintptr_t)InterlockedExchange((PLONG)(Target), (LONG)(uintptr_t)(Value))
|
||||
|
||||
|
||||
#if (_MSC_VER >= 1300)
|
||||
#if MSC_VERSION >= 1300
|
||||
typedef __w64 unsigned long *PULONG_PTR;
|
||||
#else
|
||||
typedef unsigned long *PULONG_PTR;
|
||||
|
@ -1,8 +1,8 @@
|
||||
// RAGE! Win32 OpenGL headers are full of crap we have to emulate
|
||||
// (must not include windows.h)
|
||||
|
||||
#ifndef _WIN32
|
||||
#error "do not include if not compiling for Windows"
|
||||
#if !OS_WIN
|
||||
#error "wgl.h: do not include if not compiling for Windows"
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "posix.h"
|
||||
#include "error_dialog.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
#pragma comment(lib, "shell32.lib") // for pick_directory SH* calls
|
||||
#endif
|
||||
|
||||
@ -46,7 +46,7 @@ static BOOL CALLBACK is_this_our_window(HWND hWnd, LPARAM lParam)
|
||||
{
|
||||
DWORD pid;
|
||||
DWORD tid = GetWindowThreadProcessId(hWnd, &pid);
|
||||
UNUSED(tid); // the function can't fail
|
||||
UNUSED2(tid); // the function can't fail
|
||||
|
||||
if(pid == GetCurrentProcessId())
|
||||
{
|
||||
@ -65,7 +65,7 @@ HWND win_get_app_main_window()
|
||||
{
|
||||
HWND our_window = 0;
|
||||
DWORD ret = EnumWindows(is_this_our_window, (LPARAM)&our_window);
|
||||
UNUSED(ret);
|
||||
UNUSED2(ret);
|
||||
// the callback returns FALSE when it has found the window
|
||||
// (so as not to waste time); EnumWindows then returns 0.
|
||||
// therefore, we can't check this; just return our_window.
|
||||
@ -140,9 +140,8 @@ wchar_t* get_module_filename(void* addr, wchar_t* path)
|
||||
|
||||
|
||||
|
||||
static int CALLBACK browse_cb(HWND hWnd, unsigned int msg, LPARAM lParam, LPARAM ldata)
|
||||
static int CALLBACK browse_cb(HWND hWnd, unsigned int msg, LPARAM UNUSED(lParam), LPARAM ldata)
|
||||
{
|
||||
UNUSED(lParam);
|
||||
if(msg == BFFM_INITIALIZED)
|
||||
{
|
||||
const char* cur_dir = (const char*)ldata;
|
||||
@ -397,15 +396,31 @@ static int CALLBACK error_dialog_proc(HWND hDlg, unsigned int msg, WPARAM wParam
|
||||
// exits directly if 'exit' is clicked.
|
||||
ErrorReaction display_error_impl(const wchar_t* text, int flags)
|
||||
{
|
||||
const DialogParams params = { text, flags };
|
||||
// temporarily remove any pending quit message from the queue because
|
||||
// it would prevent the dialog from being displayed (DialogBoxParam
|
||||
// returns IDOK without doing anything). will be restored below.
|
||||
// notes:
|
||||
// - this isn't only relevant at exit - Windows also posts one if
|
||||
// window init fails. therefore, it is important that errors can be
|
||||
// displayed regardless.
|
||||
// - by passing hWnd=0, we check all windows belonging to the current
|
||||
// thread. there is no reason to use hWndParent below.
|
||||
MSG msg;
|
||||
BOOL quit_pending = PeekMessage(&msg, 0, WM_QUIT, WM_QUIT, PM_REMOVE);
|
||||
|
||||
const HINSTANCE hInstance = GetModuleHandle(0);
|
||||
LPCSTR lpTemplateName = MAKEINTRESOURCE(IDD_DIALOG1);
|
||||
const DialogParams params = { text, flags };
|
||||
// get the enclosing app's window handle. we can't just pass 0 or
|
||||
// the desktop window because the dialog must be modal (the app
|
||||
// must not crash/continue to run before it has been displayed).
|
||||
const HWND hWndParent = win_get_app_main_window();
|
||||
// can't just pass 0 or desktop because this dialog must be
|
||||
// modal (the app must not crash/continue to run before this is seen).
|
||||
|
||||
INT_PTR ret = DialogBoxParam(hInstance, lpTemplateName, hWndParent, error_dialog_proc, (LPARAM)¶ms);
|
||||
|
||||
if(quit_pending)
|
||||
PostQuitMessage((int)msg.wParam);
|
||||
|
||||
// failed; warn user and make sure we return an ErrorReaction.
|
||||
if(ret == 0 || ret == -1)
|
||||
{
|
||||
@ -499,6 +514,127 @@ int clipboard_free(wchar_t* copy)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// mouse cursor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void* ptr_from_HICON(HICON hIcon)
|
||||
{
|
||||
return (void*)(uintptr_t)hIcon;
|
||||
}
|
||||
|
||||
static void* ptr_from_HCURSOR(HCURSOR hCursor)
|
||||
{
|
||||
return (void*)(uintptr_t)hCursor;
|
||||
}
|
||||
|
||||
static HICON HICON_from_ptr(void* p)
|
||||
{
|
||||
return (HICON)(uintptr_t)p;
|
||||
}
|
||||
|
||||
static HCURSOR HCURSOR_from_ptr(void* p)
|
||||
{
|
||||
return (HCURSOR)(uintptr_t)p;
|
||||
}
|
||||
|
||||
|
||||
// creates a cursor from the given 32 bpp RGBA texture. hotspot (hx,hy) is
|
||||
// the offset from its upper-left corner to the position where mouse clicks
|
||||
// are registered.
|
||||
// the cursor must be cursor_free-ed when no longer needed.
|
||||
int cursor_create(int w, int h, void* img, int hx, int hy,
|
||||
void** cursor)
|
||||
{
|
||||
*cursor = 0;
|
||||
|
||||
// convert to BGRA (required by BMP).
|
||||
// don't do this in-place so we don't spoil someone else's
|
||||
// use of the texture (however unlikely that may be).
|
||||
void* img_bgra = malloc(w*h*4);
|
||||
if(!img_bgra)
|
||||
return ERR_NO_MEM;
|
||||
const u8* src = (const u8*)img;
|
||||
u8* dst = (u8*)img_bgra;
|
||||
for(int i = 0; i < w*h; i++)
|
||||
{
|
||||
const u8 r = src[0], g = src[1], b = src[2], a = src[3];
|
||||
dst[0] = b; dst[1] = g; dst[2] = r; dst[3] = a;
|
||||
dst += 4;
|
||||
src += 4;
|
||||
}
|
||||
img = img_bgra;
|
||||
|
||||
// MSDN says selecting this HBITMAP into a DC is slower since we use
|
||||
// CreateBitmap; bpp/format must be checked against those of the DC.
|
||||
// this is the simplest way and we don't care about slight performance
|
||||
// differences because this is typically only called once.
|
||||
HBITMAP hbmColor = CreateBitmap(w, h, 1, 32, img_bgra);
|
||||
|
||||
free(img_bgra);
|
||||
|
||||
// CreateIconIndirect doesn't access it; we just need to pass
|
||||
// an empty bitmap.
|
||||
HBITMAP hbmMask = CreateBitmap(w, h, 1, 1, 0);
|
||||
|
||||
// create the cursor (really an icon; they differ only in
|
||||
// fIcon and the hotspot definitions).
|
||||
ICONINFO ii;
|
||||
ii.fIcon = FALSE; // cursor
|
||||
ii.xHotspot = hx;
|
||||
ii.yHotspot = hy;
|
||||
ii.hbmMask = hbmMask;
|
||||
ii.hbmColor = hbmColor;
|
||||
HICON hIcon = CreateIconIndirect(&ii);
|
||||
|
||||
// CreateIconIndirect makes copies, so we no longer need these.
|
||||
DeleteObject(hbmMask);
|
||||
DeleteObject(hbmColor);
|
||||
|
||||
if(!hIcon) // not INVALID_HANDLE_VALUE
|
||||
{
|
||||
debug_warn("cursor CreateIconIndirect failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*cursor = ptr_from_HICON(hIcon);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// replaces the current system cursor with the one indicated. need only be
|
||||
// called once per cursor; pass 0 to restore the default.
|
||||
int cursor_set(void* cursor)
|
||||
{
|
||||
// restore default cursor.
|
||||
if(!cursor)
|
||||
cursor = ptr_from_HCURSOR(LoadCursor(0, MAKEINTRESOURCE(IDC_ARROW)));
|
||||
|
||||
(void)SetCursor(HCURSOR_from_ptr(cursor));
|
||||
// return value (previous cursor) is useless.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// destroys the indicated cursor and frees its resources. if it is
|
||||
// currently the system cursor, the default cursor is restored first.
|
||||
int cursor_free(void* cursor)
|
||||
{
|
||||
// bail now to prevent potential confusion below; there's nothing to do.
|
||||
if(!cursor)
|
||||
return 0;
|
||||
|
||||
// if the cursor being freed is active, restore the default arrow
|
||||
// (just for safety).
|
||||
if(ptr_from_HCURSOR(GetCursor()) == cursor)
|
||||
WARN_ERR(cursor_set(0));
|
||||
|
||||
BOOL ok = DestroyIcon(HICON_from_ptr(cursor));
|
||||
return ok? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// module init and shutdown mechanism
|
||||
@ -659,9 +795,15 @@ static
|
||||
#endif
|
||||
void win_pre_main_init()
|
||||
{
|
||||
// enable FPU exceptions
|
||||
#if CPU_IA32
|
||||
const int bits = _EM_INVALID|_EM_DENORMAL|_EM_ZERODIVIDE|_EM_OVERFLOW|_EM_UNDERFLOW|_EM_INEXACT;
|
||||
_control87(bits, _MCW_EM);
|
||||
#endif
|
||||
|
||||
// enable memory tracking and leak detection;
|
||||
// no effect if !defined(HAVE_VC_DEBUG_ALLOC).
|
||||
#ifdef PARANOIA
|
||||
// no effect if !HAVE_VC_DEBUG_ALLOC.
|
||||
#if CONFIG_PARANOIA
|
||||
debug_heap_enable(DEBUG_HEAP_ALL);
|
||||
#elif !defined(NDEBUG)
|
||||
debug_heap_enable(DEBUG_HEAP_NORMAL);
|
||||
|
@ -18,8 +18,8 @@
|
||||
#ifndef WIN_H__
|
||||
#define WIN_H__
|
||||
|
||||
#ifndef _WIN32
|
||||
#error "including win.h without _WIN32 defined"
|
||||
#if !OS_WIN
|
||||
#error "win.h: do not include if not compiling for Windows"
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
// provide C99 *snprintf functions if compiler doesn't already
|
||||
// (MinGW does, VC7.1 doesn't).
|
||||
#ifndef HAVE_C99
|
||||
#if !HAVE_C99
|
||||
# define snprintf _snprintf
|
||||
# define swprintf _snwprintf
|
||||
# define vsnprintf _vsnprintf
|
||||
|
@ -18,8 +18,8 @@
|
||||
#ifndef WIN_INTERNAL_H
|
||||
#define WIN_INTERNAL_H
|
||||
|
||||
#ifndef _WIN32
|
||||
#error "including win_internal.h without _WIN32 defined"
|
||||
#if !OS_WIN
|
||||
#error "win_internal.h: do not include if not compiling for Windows"
|
||||
#endif
|
||||
|
||||
#include "lib/types.h" // intptr_t
|
||||
@ -134,7 +134,7 @@ typedef struct _MEMORYSTATUSEX
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// MinGW headers are already correct; only change on VC
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
|
||||
#ifndef NTSTATUS
|
||||
#define NTSTATUS long
|
||||
@ -244,7 +244,7 @@ typedef struct _SYSTEM_POWER_INFORMATION
|
||||
#define PO_TZ_INVALID_MODE 0 // The system does not support CPU throttling,
|
||||
// or there is no thermal zone defined [..]
|
||||
|
||||
#endif // #ifdef _MSC_VER
|
||||
#endif // #if MSC_VERSION
|
||||
|
||||
// neither VC7.1 nor MinGW define this
|
||||
typedef struct _PROCESSOR_POWER_INFORMATION
|
||||
|
@ -58,7 +58,7 @@ extern "C" {
|
||||
#define PATH_MAX 255
|
||||
// Win32 MAX_PATH is 260
|
||||
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
# ifndef SIZE_MAX // VC2005 already defines this in limits.h
|
||||
# define SIZE_MAX 0xffffffff
|
||||
# endif
|
||||
@ -131,7 +131,7 @@ EWOULDBLOCK // Operation would block (may be the same value as EAGAIN]).
|
||||
//
|
||||
|
||||
// already defined by MinGW
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
typedef unsigned int mode_t;
|
||||
#endif
|
||||
|
||||
@ -144,7 +144,7 @@ typedef unsigned int mode_t;
|
||||
// Extra hack for VC++ 2005, since it defines inline stat/fstat
|
||||
// functions inside stat.h (which get confused by the
|
||||
// macro-renaming of "stat")
|
||||
# if _MSC_VER >= 1400
|
||||
# if MSC_VERSION >= 1400
|
||||
# define RC_INVOKED // stat.h only includes stat.inl if "!defined(RC_INVOKED) && !defined(__midl)"
|
||||
# include <sys/stat.h>
|
||||
# undef RC_INVOKED
|
||||
@ -178,7 +178,6 @@ typedef void DIR;
|
||||
|
||||
struct dirent
|
||||
{
|
||||
ino_t d_ino;
|
||||
char d_name[PATH_MAX+1];
|
||||
};
|
||||
|
||||
|
@ -7,27 +7,23 @@ typedef signed char int8_t;
|
||||
typedef short int16_t;
|
||||
|
||||
// already defined by MinGW
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
typedef int int32_t;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER) || defined(__LCC__)
|
||||
#if MSC_VERSION || ICC_VERSION || LCC_VERSION
|
||||
typedef __int64 int64_t;
|
||||
#elif defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__DMC__)
|
||||
typedef long long int64_t;
|
||||
#else
|
||||
#error "port int64_t"
|
||||
typedef long long int64_t;
|
||||
#endif
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER) || defined(__LCC__)
|
||||
#if MSC_VERSION || ICC_VERSION || LCC_VERSION
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#elif defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__DMC__)
|
||||
typedef unsigned long long uint64_t;
|
||||
#else
|
||||
#error "port uint64_t"
|
||||
typedef unsigned long long uint64_t;
|
||||
#endif
|
||||
|
||||
// note: we used to define [u]intptr_t here (if not already done).
|
||||
|
@ -209,8 +209,7 @@ again:
|
||||
void* tls = pthread_getspecific(key);
|
||||
if(tls)
|
||||
{
|
||||
int ret = pthread_setspecific(key, 0);
|
||||
debug_assert(ret == 0);
|
||||
WARN_ERR(pthread_setspecific(key, 0));
|
||||
|
||||
dtor(tls);
|
||||
had_valid_tls = true;
|
||||
@ -257,10 +256,8 @@ static unsigned __stdcall thread_start(void* param)
|
||||
}
|
||||
|
||||
|
||||
int pthread_create(pthread_t* thread_id, const void* attr, void*(*func)(void*), void* user_arg)
|
||||
int pthread_create(pthread_t* thread_id, const void* UNUSED(attr), void*(*func)(void*), void* user_arg)
|
||||
{
|
||||
UNUSED(attr);
|
||||
|
||||
// tell the trampoline above what to call.
|
||||
// note: don't stack-allocate this, since the new thread might
|
||||
// not be executed before we tear down our stack frame.
|
||||
@ -387,10 +384,8 @@ int pthread_mutex_unlock(pthread_mutex_t* m)
|
||||
|
||||
// not implemented - pthread_mutex is based on CRITICAL_SECTION,
|
||||
// which doesn't support timeouts. use sem_timedwait instead.
|
||||
int pthread_mutex_timedlock(pthread_mutex_t* m, const struct timespec* abs_timeout)
|
||||
int pthread_mutex_timedlock(pthread_mutex_t* UNUSED(m), const struct timespec* UNUSED(abs_timeout))
|
||||
{
|
||||
UNUSED(m);
|
||||
UNUSED(abs_timeout);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
@ -405,8 +400,9 @@ HANDLE sem_t_to_HANDLE(sem_t* sem)
|
||||
|
||||
int sem_init(sem_t* sem, int pshared, unsigned value)
|
||||
{
|
||||
UNUSED(pshared);
|
||||
*sem = (uintptr_t)CreateSemaphore(0, (LONG)value, 0x7fffffff, 0);
|
||||
SECURITY_ATTRIBUTES sec = { sizeof(SECURITY_ATTRIBUTES) };
|
||||
sec.bInheritHandle = (BOOL)pshared;
|
||||
*sem = (uintptr_t)CreateSemaphore(&sec, (LONG)value, 0x7fffffff, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
// for easy removal of DirectDraw dependency (used to query total video mem)
|
||||
#define DDRAW
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
#pragma comment(lib, "user32.lib")
|
||||
#pragma comment(lib, "gdi32.lib")
|
||||
|
||||
@ -177,9 +177,9 @@ static LRESULT CALLBACK wndproc(HWND hWnd, unsigned int uMsg, WPARAM wParam, LPA
|
||||
}
|
||||
|
||||
|
||||
int SDL_EnableUNICODE(int enable)
|
||||
// always on (we don't care about the extra overhead)
|
||||
int SDL_EnableUNICODE(int UNUSED(enable))
|
||||
{
|
||||
UNUSED(enable)
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -478,13 +478,17 @@ static LRESULT CALLBACK keyboard_ll_hook(int nCode, WPARAM wParam, LPARAM lParam
|
||||
{
|
||||
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
|
||||
DWORD vk = p->vkCode;
|
||||
UNUSED2(vk);
|
||||
|
||||
// disabled - we want the normal Windows printscreen handling to
|
||||
// remain so as not to confuse artists.
|
||||
/*
|
||||
// replace Windows PrintScreen handler
|
||||
if(vk == VK_SNAPSHOT)
|
||||
{
|
||||
// check whether PrintScreen should be taking screenshots -- if
|
||||
// not, allow the standard Windows clipboard to work
|
||||
if(/*keyRespondsTo(HOTKEY_SCREENSHOT, SDLK_PRINT) &&*/ app_active)
|
||||
if(app_active)
|
||||
{
|
||||
// send to wndproc
|
||||
UINT msg = (UINT)wParam;
|
||||
@ -496,6 +500,7 @@ static LRESULT CALLBACK keyboard_ll_hook(int nCode, WPARAM wParam, LPARAM lParam
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// pass it on to other hook handlers
|
||||
@ -505,7 +510,6 @@ static LRESULT CALLBACK keyboard_ll_hook(int nCode, WPARAM wParam, LPARAM lParam
|
||||
|
||||
static void enable_kbd_hook(bool enable)
|
||||
{
|
||||
/*
|
||||
if(enable)
|
||||
{
|
||||
debug_assert(hKeyboard_LL_Hook == 0);
|
||||
@ -518,7 +522,6 @@ static void enable_kbd_hook(bool enable)
|
||||
UnhookWindowsHookEx(hKeyboard_LL_Hook);
|
||||
hKeyboard_LL_Hook = 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@ -582,10 +585,8 @@ static int wsdl_shutdown()
|
||||
}
|
||||
|
||||
|
||||
int SDL_Init(Uint32 flags)
|
||||
int SDL_Init(Uint32 UNUSED(flags))
|
||||
{
|
||||
UNUSED(flags);
|
||||
|
||||
enable_kbd_hook(true);
|
||||
|
||||
return 0;
|
||||
@ -843,7 +844,7 @@ void SDL_WM_SetCaption(const char* title, const char* icon)
|
||||
{
|
||||
SetWindowText(hWnd, title);
|
||||
|
||||
UNUSED(icon); // TODO: implement
|
||||
UNUSED2(icon); // TODO: implement
|
||||
}
|
||||
|
||||
|
||||
@ -1094,11 +1095,8 @@ void glutMouseFunc(void (*func)(int, int, int, int))
|
||||
|
||||
|
||||
|
||||
void glutInit(int* argc, char* argv[])
|
||||
void glutInit(int* UNUSED(argc), char* UNUSED(argv)[])
|
||||
{
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
SDL_Init(0);
|
||||
atexit(SDL_Quit);
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ extern int SDL_SetGamma(float r, float g, float b);
|
||||
|
||||
// Debug-mode ICC doesn't like the intrinsics, so only use them
|
||||
// for MSVC and non-debug ICC.
|
||||
#if defined(_MSC_VER) && !( defined(__INTEL_COMPILER) && !defined(NDEBUG) )
|
||||
#if MSC_VERSION && !( defined(__INTEL_COMPILER) && !defined(NDEBUG) )
|
||||
extern unsigned short _byteswap_ushort(unsigned short);
|
||||
extern unsigned long _byteswap_ulong(unsigned long);
|
||||
extern unsigned __int64 _byteswap_uint64(unsigned __int64);
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if MSC_VERSION
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#endif
|
||||
|
||||
|
@ -165,7 +165,7 @@ static int choose_impl()
|
||||
if(overrides[impl] == HRT_FORCE)\
|
||||
safe = true;
|
||||
|
||||
#if defined(_M_IX86) && !defined(NO_TSC)
|
||||
#if CPU_IA32 && !defined(NO_TSC)
|
||||
// CPU Timestamp Counter (incremented every clock)
|
||||
// ns resolution, moderate precision (poor clock crystal?)
|
||||
//
|
||||
@ -201,7 +201,7 @@ static int choose_impl()
|
||||
}
|
||||
#endif // TSC
|
||||
|
||||
#if defined(_WIN32) && !defined(NO_QPC)
|
||||
#if OS_WIN && !defined(NO_QPC)
|
||||
// Windows QueryPerformanceCounter API
|
||||
// implementations:
|
||||
// - PIT on Win2k - 838 ns resolution, slow to read (~3 µs)
|
||||
@ -295,13 +295,13 @@ static i64 ticks_lk()
|
||||
switch(hrt_impl)
|
||||
{
|
||||
// TSC
|
||||
#if defined(_M_IX86) && !defined(NO_TSC)
|
||||
#if CPU_IA32 && !defined(NO_TSC)
|
||||
case HRT_TSC:
|
||||
return (i64)rdtsc();
|
||||
#endif
|
||||
|
||||
// QPC
|
||||
#if defined(_WIN32) && !defined(NO_QPC)
|
||||
#if OS_WIN && !defined(NO_QPC)
|
||||
case HRT_QPC:
|
||||
{
|
||||
LARGE_INTEGER i;
|
||||
@ -312,7 +312,7 @@ static i64 ticks_lk()
|
||||
#endif
|
||||
|
||||
// TGT
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
case HRT_GTC:
|
||||
return (i64)GetTickCount();
|
||||
#endif
|
||||
@ -488,7 +488,7 @@ static const long safe_timer_freq = 1000;
|
||||
|
||||
static long safe_time()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if OS_WIN
|
||||
return (long)GetTickCount();
|
||||
#else
|
||||
return (long)(clock() * 1000.0 / CLOCKS_PER_SEC);
|
||||
@ -561,9 +561,9 @@ static void calibrate_lk()
|
||||
static pthread_t thread;
|
||||
static sem_t exit_flag;
|
||||
|
||||
static void* calibration_thread(void* data)
|
||||
static void* calibration_thread(void* UNUSED(data))
|
||||
{
|
||||
UNUSED(data);
|
||||
debug_set_thread_name("wtime");
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@ -808,10 +808,8 @@ int nanosleep(const struct timespec* rqtp, struct timespec* /* rmtp */)
|
||||
}
|
||||
|
||||
|
||||
int gettimeofday(struct timeval* tv, void* tzp)
|
||||
int gettimeofday(struct timeval* tv, void* UNUSED(tzp))
|
||||
{
|
||||
UNUSED(tzp);
|
||||
|
||||
const long us = (long)(time_ns() / 1000);
|
||||
tv->tv_sec = (time_t) (us / _1e6);
|
||||
tv->tv_usec = (suseconds_t)(us % _1e6);
|
||||
|
@ -18,9 +18,12 @@
|
||||
#ifndef WTIME_H__
|
||||
#define WTIME_H__
|
||||
|
||||
|
||||
#define HAVE_CLOCK_GETTIME
|
||||
#define HAVE_GETTIMEOFDAY
|
||||
// advertise support for the timer routines we emulate; used by timer.cpp.
|
||||
// #undef to avoid macro redefinition warning.
|
||||
#undef HAVE_CLOCK_GETTIME
|
||||
#define HAVE_CLOCK_GETTIME 1
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
|
||||
|
||||
//
|
||||
@ -70,7 +73,7 @@ extern int clock_gettime(clockid_t clock, struct timespec* ts);
|
||||
extern int clock_getres(clockid_t clock, struct timespec* res);
|
||||
|
||||
|
||||
// HACK: if _WIN32, the HRT makes its final implementation choice
|
||||
// HACK: on Windows, the HRT makes its final implementation choice
|
||||
// in the first calibrate call where cpu_freq is available.
|
||||
// provide a routine that makes the choice when called,
|
||||
// so app code isn't surprised by a timer change, although the HRT
|
||||
|
@ -36,7 +36,7 @@ double get_time()
|
||||
{
|
||||
double t;
|
||||
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
|
||||
static struct timespec start = {0};
|
||||
struct timespec ts;
|
||||
@ -47,7 +47,7 @@ double get_time()
|
||||
(void)clock_gettime(CLOCK_REALTIME, &ts);
|
||||
t = (ts.tv_sec - start.tv_sec) + (ts.tv_nsec - start.tv_nsec)*1e-9;
|
||||
|
||||
#elif defined(HAVE_GETTIMEOFDAY)
|
||||
#elif HAVE_GETTIMEOFDAY
|
||||
|
||||
static struct timeval start;
|
||||
struct timeval cur;
|
||||
@ -83,7 +83,7 @@ double timer_res()
|
||||
|
||||
double res = 0.0;
|
||||
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
|
||||
struct timespec ts;
|
||||
if(clock_getres(CLOCK_REALTIME, &ts) == 0)
|
||||
|
Loading…
Reference in New Issue
Block a user