From 7eb7ac5e3c038e55262f90fabd9ed770a1c941fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Wed, 14 Nov 2007 12:18:37 +0000 Subject: [PATCH] Use Wine debug channel infrastructure. I modified it a bit to match our debug message format To test it, set DEBUGCHANNEL environment variable to what you want to see, and run your program. Syntax: set DEBUGCHANNEL = [[fixme|err|warn|trace]+|-{channel}|all]* svn path=/trunk/; revision=30438 --- reactos/include/reactos/wine/debug.h | 363 ++++++++++++++------- reactos/lib/3rdparty/libwine/debug.c | 454 +++++++++++++++++++-------- 2 files changed, 575 insertions(+), 242 deletions(-) diff --git a/reactos/include/reactos/wine/debug.h b/reactos/include/reactos/wine/debug.h index 9763fac68b8..6eeb5443972 100644 --- a/reactos/include/reactos/wine/debug.h +++ b/reactos/include/reactos/wine/debug.h @@ -1,51 +1,204 @@ +/* + * Wine debugging interface + * + * Copyright 1999 Patrik Stridvall + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + #ifndef __WINE_DEBUG_H #define __WINE_DEBUG_H -#include "../roscfg.h" #include #include -#if !defined(_MSC_VER) -#include +#ifndef GUID_DEFINED +#include #endif -/* Add ROS Master debug functions if not added yet */ -#ifndef __INTERNAL_DEBUG -#ifdef YDEBUG -#undef NDEBUG -#else -#define NDEBUG -#endif -#include +#ifdef __WINE_WINE_TEST_H +#error This file should not be used in Wine tests #endif -#ifndef __GNUC__ -#if !defined(_MSC_VER) || _MSC_VER < 8 -#define __FUNCTION__ "" -#endif//_MSC_VER -#define inline __inline +#ifdef __cplusplus +extern "C" { #endif -ULONG DbgPrint(const char *Format,...); - struct _GUID; -/* Exported definitions and macros */ +/* + * Internal definitions (do not use these directly) + */ -/* These function return a printable version of a string, including +enum __wine_debug_class +{ + __WINE_DBCL_FIXME = 0, /* 0x1 */ + __WINE_DBCL_ERR = 1, /* 0x2 */ + __WINE_DBCL_WARN = 2, /* 0x4 */ + __WINE_DBCL_TRACE = 3, /* 0x8 */ + + /* lazy init flag */ +#ifdef YDEBUG + __WINE_DBCL_INIT = 0xf +#else + __WINE_DBCL_INIT = 0x7 +#endif +}; + +struct __wine_debug_channel +{ + unsigned char flags; + char name[15]; +}; + +#define UNIMPLEMENTED WINE_FIXME(" is unimplemented") + +#ifndef WINE_NO_TRACE_MSGS +# define __WINE_GET_DEBUGGING_TRACE(dbch) ((dbch)->flags & (1 << __WINE_DBCL_TRACE)) +#else +# define __WINE_GET_DEBUGGING_TRACE(dbch) 0 +#endif + +#ifndef WINE_NO_DEBUG_MSGS +# define __WINE_GET_DEBUGGING_WARN(dbch) ((dbch)->flags & (1 << __WINE_DBCL_WARN)) +# define __WINE_GET_DEBUGGING_FIXME(dbch) ((dbch)->flags & (1 << __WINE_DBCL_FIXME)) +#else +# define __WINE_GET_DEBUGGING_WARN(dbch) 0 +# define __WINE_GET_DEBUGGING_FIXME(dbch) 0 +#endif + +/* define error macro regardless of what is configured */ +#define __WINE_GET_DEBUGGING_ERR(dbch) ((dbch)->flags & (1 << __WINE_DBCL_ERR)) + +#define __WINE_GET_DEBUGGING(dbcl,dbch) __WINE_GET_DEBUGGING##dbcl(dbch) + +#define __WINE_IS_DEBUG_ON(dbcl,dbch) \ + (__WINE_GET_DEBUGGING##dbcl(dbch) && (__wine_dbg_get_channel_flags(dbch) & (1 << __WINE_DBCL##dbcl))) + +#ifdef __GNUC__ + +#define __WINE_DPRINTF(dbcl,dbch) \ + do { if(__WINE_GET_DEBUGGING(dbcl,(dbch))) { \ + struct __wine_debug_channel * const __dbch = (dbch); \ + const enum __wine_debug_class __dbcl = __WINE_DBCL##dbcl; \ + __WINE_DBG_LOG + +#define __WINE_DBG_LOG(args...) \ + wine_dbg_log( __dbcl, __dbch, __FILE__, __FUNCTION__, __LINE__, args); } } while(0) + +#define __WINE_PRINTF_ATTR(fmt,args) /*__attribute__((format (printf,fmt,args)))*/ + + +#ifdef WINE_NO_TRACE_MSGS +#define WINE_TRACE(args...) do { } while(0) +#define WINE_TRACE_(ch) WINE_TRACE +#endif + +#ifdef WINE_NO_DEBUG_MSGS +#define WINE_WARN(args...) do { } while(0) +#define WINE_WARN_(ch) WINE_WARN +#define WINE_FIXME(args...) do { } while(0) +#define WINE_FIXME_(ch) WINE_FIXME +#endif + +#elif defined(__SUNPRO_C) + +#define __WINE_DPRINTF(dbcl,dbch) \ + do { if(__WINE_GET_DEBUGGING(dbcl,(dbch))) { \ + struct __wine_debug_channel * const __dbch = (dbch); \ + const enum __WINE_DEBUG_CLASS __dbcl = __WINE_DBCL##dbcl; \ + __WINE_DBG_LOG + +#define __WINE_DBG_LOG(...) \ + wine_dbg_log( __dbcl, __dbch, __func__, __VA_ARGS__); } } while(0) + +#define __WINE_PRINTF_ATTR(fmt,args) + +#ifdef WINE_NO_TRACE_MSGS +#define WINE_TRACE(...) do { } while(0) +#define WINE_TRACE_(ch) WINE_TRACE +#endif + +#ifdef WINE_NO_DEBUG_MSGS +#define WINE_WARN(...) do { } while(0) +#define WINE_WARN_(ch) WINE_WARN +#define WINE_FIXME(...) do { } while(0) +#define WINE_FIXME_(ch) WINE_FIXME +#endif + +#else /* !__GNUC__ && !__SUNPRO_C */ + +#define __WINE_DPRINTF(dbcl,dbch) \ + (!__WINE_GET_DEBUGGING(dbcl,(dbch)) || \ + (wine_dbg_log(__WINE_DBCL##dbcl,(dbch),__FILE__,"",__LINE__,"") == -1)) ? \ + (void)0 : (void)wine_dbg_printf + +#define __WINE_PRINTF_ATTR(fmt, args) + +#endif /* !__GNUC__ && !__SUNPRO_C */ + +struct __wine_debug_functions +{ + char * (*get_temp_buffer)( size_t n ); + void (*release_temp_buffer)( char *buffer, size_t n ); + const char * (*dbgstr_an)( const char * s, int n ); + const char * (*dbgstr_wn)( const WCHAR *s, int n ); + int (*dbg_vprintf)( const char *format, va_list args ); + int (*dbg_vlog)( enum __wine_debug_class cls, struct __wine_debug_channel *channel, + const char *file, const char *function, const int line, const char *format, va_list args ); +}; + +extern unsigned char __wine_dbg_get_channel_flags( struct __wine_debug_channel *channel ); +extern int __wine_dbg_set_channel_flags( struct __wine_debug_channel *channel, + unsigned char set, unsigned char clear ); +extern void __wine_dbg_set_functions( const struct __wine_debug_functions *new_funcs, + struct __wine_debug_functions *old_funcs, size_t size ); + +/* + * Exported definitions and macros + */ + +/* These functions return a printable version of a string, including quotes. The string will be valid for some time, but not indefinitely as strings are re-used. */ -extern const char *wine_dbgstr_w( const WCHAR *s ); extern const char *wine_dbgstr_an( const char * s, int n ); -extern const char *wine_dbgstr_wn( const wchar_t *s, int n ); -extern const char *wine_dbgstr_longlong( unsigned long long ll ); -extern const char *wine_dbg_sprintf( const char *format, ... ); +extern const char *wine_dbgstr_wn( const WCHAR *s, int n ); +extern const char *wine_dbg_sprintf( const char *format, ... ) __WINE_PRINTF_ATTR(1,2); -inline static const char *debugstr_an( const char * s, int n ) { return wine_dbgstr_an( s, n ); } -inline static const char *debugstr_wn( const wchar_t *s, int n ) { return wine_dbgstr_wn( s, n ); } -inline static const char *debugstr_a( const char *s ) { return wine_dbgstr_an( s, 80 ); } -inline static const char *debugstr_w( const wchar_t *s ) { return wine_dbgstr_wn( s, 80 ); } -inline static const char *debugres_a( const char *s ) { return wine_dbgstr_an( s, 80 ); } -inline static const char *debugres_w( const wchar_t *s ) { return wine_dbgstr_wn( s, 80 ); } +extern int wine_dbg_printf( const char *format, ... ) __WINE_PRINTF_ATTR(1,2); +extern int wine_dbg_log( enum __wine_debug_class cls, struct __wine_debug_channel *ch, const char *file, + const char *func, const int line, const char *format, ... ) __WINE_PRINTF_ATTR(6,7); + +static inline const char *wine_dbgstr_a( const char *s ) +{ + return wine_dbgstr_an( s, -1 ); +} + +static inline const char *wine_dbgstr_w( const WCHAR *s ) +{ + return wine_dbgstr_wn( s, -1 ); +} + +static inline const char *wine_dbgstr_guid( const GUID *id ) +{ + if (!id) return "(null)"; + if (!((INT_PTR)id >> 16)) return wine_dbg_sprintf( "", (INT_PTR)id & 0xffff ); + return wine_dbg_sprintf( "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + id->Data1, id->Data2, id->Data3, + id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], + id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); +} static inline const char *wine_dbgstr_point( const POINT *pt ) { @@ -62,98 +215,78 @@ static inline const char *wine_dbgstr_size( const SIZE *size ) static inline const char *wine_dbgstr_rect( const RECT *rect ) { if (!rect) return "(null)"; - return wine_dbg_sprintf( "(%ld,%ld)-(%ld,%ld)", rect->left, rect->top, rect->right, rect->bottom ); + return wine_dbg_sprintf( "(%ld,%ld)-(%ld,%ld)", rect->left, rect->top, + rect->right, rect->bottom ); } -static inline const char *wine_dbgstr_guid( const GUID *id ) +static inline const char *wine_dbgstr_longlong( ULONGLONG ll ) { - if (!id) return "(null)"; - if (!((INT_PTR)id >> 16)) return wine_dbg_sprintf( "", (INT_PTR)id & 0xffff ); - return wine_dbg_sprintf( "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - id->Data1, id->Data2, id->Data3, - id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], - id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); + if (sizeof(ll) > sizeof(unsigned long) && ll >> 32) + return wine_dbg_sprintf( "%lx%08lx", (unsigned long)(ll >> 32), (unsigned long)ll ); + else return wine_dbg_sprintf( "%lx", (unsigned long)ll ); } +#ifndef WINE_TRACE +#define WINE_TRACE __WINE_DPRINTF(_TRACE,__wine_dbch___default) +#define WINE_TRACE_(ch) __WINE_DPRINTF(_TRACE,&__wine_dbch_##ch) +#endif +#define WINE_TRACE_ON(ch) __WINE_IS_DEBUG_ON(_TRACE,&__wine_dbch_##ch) + +#ifndef WINE_WARN +#define WINE_WARN __WINE_DPRINTF(_WARN,__wine_dbch___default) +#define WINE_WARN_(ch) __WINE_DPRINTF(_WARN,&__wine_dbch_##ch) +#endif +#define WINE_WARN_ON(ch) __WINE_IS_DEBUG_ON(_WARN,&__wine_dbch_##ch) + +#ifndef WINE_FIXME +#define WINE_FIXME __WINE_DPRINTF(_FIXME,__wine_dbch___default) +#define WINE_FIXME_(ch) __WINE_DPRINTF(_FIXME,&__wine_dbch_##ch) +#endif +#define WINE_FIXME_ON(ch) __WINE_IS_DEBUG_ON(_FIXME,&__wine_dbch_##ch) + +#define WINE_ERR __WINE_DPRINTF(_ERR,__wine_dbch___default) +#define WINE_ERR_(ch) __WINE_DPRINTF(_ERR,&__wine_dbch_##ch) +#define WINE_ERR_ON(ch) __WINE_IS_DEBUG_ON(_ERR,&__wine_dbch_##ch) + +#define WINE_DECLARE_DEBUG_CHANNEL(ch) \ + static struct __wine_debug_channel __wine_dbch_##ch = { ~0, #ch } +#define WINE_DEFAULT_DEBUG_CHANNEL(ch) \ + static struct __wine_debug_channel __wine_dbch_##ch = { ~0, #ch }; \ + static struct __wine_debug_channel * const __wine_dbch___default = &__wine_dbch_##ch + +#define WINE_DPRINTF wine_dbg_printf +#define WINE_MESSAGE wine_dbg_printf + +/* Wine uses shorter names that are very likely to conflict with other software */ + +static inline const char *debugstr_an( const char * s, int n ) { return wine_dbgstr_an( s, n ); } +static inline const char *debugstr_wn( const WCHAR *s, int n ) { return wine_dbgstr_wn( s, n ); } static inline const char *debugstr_guid( const struct _GUID *id ) { return wine_dbgstr_guid(id); } +static inline const char *debugstr_a( const char *s ) { return wine_dbgstr_an( s, -1 ); } +static inline const char *debugstr_w( const WCHAR *s ) { return wine_dbgstr_wn( s, -1 ); } -#define TRACE DPRINT -#define TRACE_(ch) DPRINT -#ifdef NDEBUG -#define TRACE_ON(ch) 0 -#else -#define TRACE_ON(ch) 1 +#define TRACE WINE_TRACE +#define TRACE_(ch) WINE_TRACE_(ch) +#define TRACE_ON(ch) WINE_TRACE_ON(ch) + +#define WARN WINE_WARN +#define WARN_(ch) WINE_WARN_(ch) +#define WARN_ON(ch) WINE_WARN_ON(ch) + +#define FIXME WINE_FIXME +#define FIXME_(ch) WINE_FIXME_(ch) +#define FIXME_ON(ch) WINE_FIXME_ON(ch) + +#undef ERR /* Solaris got an 'ERR' define in */ +#define ERR WINE_ERR +#define ERR_(ch) WINE_ERR_(ch) +#define ERR_ON(ch) WINE_ERR_ON(ch) + +#define DPRINTF WINE_DPRINTF +#define MESSAGE WINE_MESSAGE + +#ifdef __cplusplus +} #endif -#define WINE_TRACE DPRINT -#define WINE_TRACE_(ch) DPRINT -#ifdef NDEBUG -#define WINE_TRACE_ON(ch) 0 -#else -#define WINE_TRACE_ON(ch) 1 -#endif - -#define WARN DPRINT -#define WARN_(ch) DPRINT -#ifdef NDEBUG -#define WARN_ON(ch) 0 -#else -#define WARN_ON(ch) 1 -#endif - -#define WINE_WARN DPRINT -#define WINE_WARN_(ch) DPRINT -#ifdef NDEBUG -#define WINE_WARN_ON(ch) 0 -#else -#define WINE_WARN_ON(ch) 1 -#endif - -#ifdef FIXME -#undef FIXME -#endif -#define FIXME DPRINT1 -#define FIXME_(ch) DPRINT1 -#ifdef NDEBUG -#define FIXME_ON(ch) 0 -#else -#define FIXME_ON(ch) 1 -#endif - -#ifdef WINE_FIXME -#undef WINE_FIXME -#endif -#define WINE_FIXME DPRINT1 -#define WINE_FIXME_(ch) DPRINT1 -#ifdef NDEBUG -#define WINE_FIXME_ON(ch) 0 -#else -#define WINE_FIXME_ON(ch) 1 -#endif - -#define ERR DPRINT1 -#define ERR_(ch) DPRINT1 -#ifdef NDEBUG -#define ERR_ON(ch) 0 -#else -#define ERR_ON(ch) 1 -#endif - -#define WINE_ERR DPRINT1 -#define WINE_ERR_(ch) DPRINT1 -#ifdef NDEBUG -#define WINE_ERR_ON(ch) 0 -#else -#define WINE_ERR_ON(ch) 1 -#endif - -#define DECLARE_DEBUG_CHANNEL(ch) -#define DEFAULT_DEBUG_CHANNEL(ch) - -#define WINE_DECLARE_DEBUG_CHANNEL(ch) DECLARE_DEBUG_CHANNEL(ch) -#define WINE_DEFAULT_DEBUG_CHANNEL(ch) DEFAULT_DEBUG_CHANNEL(ch) - -#define DPRINTF DPRINT -#define MESSAGE DPRINT - #endif /* __WINE_DEBUG_H */ diff --git a/reactos/lib/3rdparty/libwine/debug.c b/reactos/lib/3rdparty/libwine/debug.c index 8d5b84347a6..5af7274e8e1 100644 --- a/reactos/lib/3rdparty/libwine/debug.c +++ b/reactos/lib/3rdparty/libwine/debug.c @@ -15,125 +15,289 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include +#include "wine/config.h" +#include "wine/port.h" + #include #include -#include +#include +#include +#include +#include -#include -#include -#include +#define WIN32_NO_STATUS +#include "wine/debug.h" +#include "wine/library.h" -/* ---------------------------------------------------------------------- */ +#include +#include -static CRITICAL_SECTION WineDebugCS; -static CRITICAL_SECTION_DEBUG critsect_debug = +#define KEY_QUERY_VALUE 1 +#define REG_SZ 1 + +ULONG +__cdecl +DbgPrint( + IN PCCH Format, + IN ... +); + +static const char * const debug_classes[] = { "fixme", "err", "warn", "trace" }; + +#define MAX_DEBUG_OPTIONS 256 + +static unsigned char default_flags = (1 << __WINE_DBCL_ERR) | (1 << __WINE_DBCL_FIXME); +static int nb_debug_options = -1; +static struct __wine_debug_channel debug_options[MAX_DEBUG_OPTIONS]; + +static struct __wine_debug_functions funcs; + +static void debug_init(void); + +static int cmp_name( const void *p1, const void *p2 ) { - 0, 0, &WineDebugCS, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { 0, 0 } -}; -static CRITICAL_SECTION WineDebugCS = { &critsect_debug, -1, 0, 0, 0, 0 }; -static DWORD WineDebugTlsIndex = TLS_OUT_OF_INDEXES; + const char *name = p1; + const struct __wine_debug_channel *chan = p2; + return strcmp( name, chan->name ); +} -/* ---------------------------------------------------------------------- */ - -struct debug_info +/* get the flags to use for a given channel, possibly setting them too in case of lazy init */ +unsigned char __wine_dbg_get_channel_flags( struct __wine_debug_channel *channel ) { - char *str_pos; /* current position in strings buffer */ - char *out_pos; /* current position in output buffer */ - char strings[1024]; /* buffer for temporary strings */ - char output[1024]; /* current output line */ -}; + if (nb_debug_options == -1) debug_init(); -static struct debug_info tmp = { tmp.strings, tmp.output }; - -/* get the debug info pointer for the current thread */ -static inline struct debug_info *get_info(void) -{ - struct debug_info *info; - - if (WineDebugTlsIndex == TLS_OUT_OF_INDEXES) + if (nb_debug_options) { - EnterCriticalSection(&WineDebugCS); - if (WineDebugTlsIndex == TLS_OUT_OF_INDEXES) - { - DWORD NewTlsIndex = TlsAlloc(); - if (NewTlsIndex == TLS_OUT_OF_INDEXES) - { - LeaveCriticalSection(&WineDebugCS); - return &tmp; - } - info = HeapAlloc(GetProcessHeap(), 0, sizeof(*info)); - if (!info) - { - LeaveCriticalSection(&WineDebugCS); - TlsFree(NewTlsIndex); - return &tmp; - } - info->str_pos = info->strings; - info->out_pos = info->output; - TlsSetValue(NewTlsIndex, info); - WineDebugTlsIndex = NewTlsIndex; - } - LeaveCriticalSection(&WineDebugCS); + struct __wine_debug_channel *opt = bsearch( channel->name, debug_options, nb_debug_options, + sizeof(debug_options[0]), cmp_name ); + if (opt) return opt->flags; } - - return TlsGetValue(WineDebugTlsIndex); + /* no option for this channel */ + if (channel->flags & (1 << __WINE_DBCL_INIT)) channel->flags = default_flags; + return default_flags; } -/* allocate some tmp space for a string */ -static void *gimme1(int n) +/* set the flags to use for a given channel; return 0 if the channel is not available to set */ +int __wine_dbg_set_channel_flags( struct __wine_debug_channel *channel, + unsigned char set, unsigned char clear ) { - struct debug_info *info = get_info(); - char *res = info->str_pos; + if (nb_debug_options == -1) debug_init(); - if (res + n >= &info->strings[sizeof(info->strings)]) res = info->strings; - info->str_pos = res + n; - return res; -} - -/* release extra space that we requested in gimme1() */ -static inline void release(void *ptr) -{ - struct debug_info *info; - if (WineDebugTlsIndex == TLS_OUT_OF_INDEXES) - info = &tmp; - else - info = TlsGetValue(WineDebugTlsIndex); - info->str_pos = ptr; -} - -/*********************************************************************** - * wine_dbgstr_an - */ -const char *wine_dbgstr_an(const char *src, int n) -{ - char *dst, *res; - - if (!HIWORD(src)) + if (nb_debug_options) { - if (!src) return "(null)"; - res = gimme1(6); - sprintf(res, "#%04x", (WORD)(DWORD)(src) ); + struct __wine_debug_channel *opt = bsearch( channel->name, debug_options, nb_debug_options, + sizeof(debug_options[0]), cmp_name ); + if (opt) + { + opt->flags = (opt->flags & ~clear) | set; + return 1; + } + } + return 0; +} + +/* add a new debug option at the end of the option list */ +static void add_option( const char *name, unsigned char set, unsigned char clear ) +{ + int min = 0, max = nb_debug_options - 1, pos, res; + + if (!name[0]) /* "all" option */ + { + default_flags = (default_flags & ~clear) | set; + return; + } + if (strlen(name) >= sizeof(debug_options[0].name)) return; + + while (min <= max) + { + pos = (min + max) / 2; + res = strcmp( name, debug_options[pos].name ); + if (!res) + { + debug_options[pos].flags = (debug_options[pos].flags & ~clear) | set; + return; + } + if (res < 0) max = pos - 1; + else min = pos + 1; + } + if (nb_debug_options >= MAX_DEBUG_OPTIONS) return; + + pos = min; + if (pos < nb_debug_options) memmove( &debug_options[pos + 1], &debug_options[pos], + (nb_debug_options - pos) * sizeof(debug_options[0]) ); + strcpy( debug_options[pos].name, name ); + debug_options[pos].flags = (default_flags & ~clear) | set; + nb_debug_options++; +} + +/* parse a set of debugging option specifications and add them to the option list */ +static void parse_options( char *options ) +{ + char *opt, *next; + unsigned int i; + + for (opt = options; opt; opt = next) + { + const char *p; + unsigned char set = 0, clear = 0; + + if ((next = strchr( opt, ',' ))) *next++ = 0; + + p = opt + strcspn( opt, "+-" ); + if (!p[0]) p = opt; /* assume it's a debug channel name */ + + if (p > opt) + { + for (i = 0; i < sizeof(debug_classes)/sizeof(debug_classes[0]); i++) + { + int len = strlen(debug_classes[i]); + if (len != (p - opt)) continue; + if (!memcmp( opt, debug_classes[i], len )) /* found it */ + { + if (*p == '+') set |= 1 << i; + else clear |= 1 << i; + break; + } + } + if (i == sizeof(debug_classes)/sizeof(debug_classes[0])) /* bad class name, skip it */ + continue; + } + else + { + if (*p == '-') clear = ~0; + else set = ~0; + } + if (*p == '+' || *p == '-') p++; + if (!p[0]) continue; + + if (!strcmp( p, "all" )) + default_flags = (default_flags & ~clear) | set; + else + add_option( p, set, clear ); + } +} + +/* initialize all options at startup */ +static void debug_init(void) +{ + char *wine_debug; + DWORD dwLength; + + if (nb_debug_options != -1) return; /* already initialized */ + nb_debug_options = 0; + + dwLength = GetEnvironmentVariableA("DEBUGCHANNEL", NULL, 0); + if (dwLength) + { + wine_debug = malloc(dwLength); + if (wine_debug) + { + if (GetEnvironmentVariableA("DEBUGCHANNEL", wine_debug, dwLength) < dwLength) + parse_options(wine_debug); + free(wine_debug); + } + } +} + +/* varargs wrapper for funcs.dbg_vprintf */ +int wine_dbg_printf( const char *format, ... ) +{ + int ret; + va_list valist; + + va_start(valist, format); + ret = funcs.dbg_vprintf( format, valist ); + va_end(valist); + return ret; +} + +/* printf with temp buffer allocation */ +const char *wine_dbg_sprintf( const char *format, ... ) +{ + static const int max_size = 200; + char *ret; + int len; + va_list valist; + + va_start(valist, format); + ret = funcs.get_temp_buffer( max_size ); + len = vsnprintf( ret, max_size, format, valist ); + if (len == -1 || len >= max_size) ret[max_size-1] = 0; + else funcs.release_temp_buffer( ret, len + 1 ); + va_end(valist); + return ret; +} + + +/* varargs wrapper for funcs.dbg_vlog */ +int wine_dbg_log( enum __wine_debug_class cls, struct __wine_debug_channel *channel, + const char *file, const char *func, const int line, const char *format, ... ) +{ + int ret; + va_list valist; + + if (!(__wine_dbg_get_channel_flags( channel ) & (1 << cls))) return -1; + + va_start(valist, format); + ret = funcs.dbg_vlog( cls, channel, file, func, line, format, valist ); + va_end(valist); + return ret; +} + + +/* allocate some tmp string space */ +/* FIXME: this is not 100% thread-safe */ +static char *get_temp_buffer( size_t size ) +{ + static char *list[32]; + static long pos; + char *ret; + int idx; + + idx = interlocked_xchg_add( &pos, 1 ) % (sizeof(list)/sizeof(list[0])); + if ((ret = realloc( list[idx], size ))) list[idx] = ret; + return ret; +} + + +/* release unused part of the buffer */ +static void release_temp_buffer( char *buffer, size_t size ) +{ + /* don't bother doing anything */ +} + + +/* default implementation of wine_dbgstr_an */ +static const char *default_dbgstr_an( const char *str, int n ) +{ + static const char hex[16] = "0123456789abcdef"; + char *dst, *res; + size_t size; + + if (!((ULONG_PTR)str >> 16)) + { + if (!str) return "(null)"; + res = funcs.get_temp_buffer( 6 ); + sprintf( res, "#%04x", LOWORD(str) ); return res; } + if (n == -1) n = strlen(str); if (n < 0) n = 0; - else if (n > 200) n = 200; - dst = res = gimme1 (n * 4 + 6); + size = 10 + min( 300, n * 4 ); + dst = res = funcs.get_temp_buffer( size ); *dst++ = '"'; - while (n-- > 0 && *src) + while (n-- > 0 && dst <= res + size - 9) { - unsigned char c = *src++; + unsigned char c = *str++; switch (c) { case '\n': *dst++ = '\\'; *dst++ = 'n'; break; case '\r': *dst++ = '\\'; *dst++ = 'r'; break; case '\t': *dst++ = '\\'; *dst++ = 't'; break; - case '"': *dst++ = '\\'; *dst++ = '"'; break; + case '"': *dst++ = '\\'; *dst++ = '"'; break; case '\\': *dst++ = '\\'; *dst++ = '\\'; break; default: if (c >= ' ' && c <= 126) @@ -141,52 +305,58 @@ const char *wine_dbgstr_an(const char *src, int n) else { *dst++ = '\\'; - *dst++ = '0' + ((c >> 6) & 7); - *dst++ = '0' + ((c >> 3) & 7); - *dst++ = '0' + ((c >> 0) & 7); + *dst++ = 'x'; + *dst++ = hex[(c >> 4) & 0x0f]; + *dst++ = hex[c & 0x0f]; } } } *dst++ = '"'; - if (*src) + if (n > 0) { *dst++ = '.'; *dst++ = '.'; *dst++ = '.'; } - *dst++ = '\0'; - release( dst ); + *dst++ = 0; + funcs.release_temp_buffer( res, dst - res ); return res; } -/*********************************************************************** - * wine_dbgstr_wn - */ -const char *wine_dbgstr_wn(const WCHAR *src, int n) + +/* default implementation of wine_dbgstr_wn */ +static const char *default_dbgstr_wn( const WCHAR *str, int n ) { char *dst, *res; + size_t size; - if (!HIWORD(src)) + if (!((ULONG_PTR)str >> 16)) { - if (!src) return "(null)"; - res = gimme1(6); - sprintf(res, "#%04x", (WORD)(DWORD)(src) ); + if (!str) return "(null)"; + res = funcs.get_temp_buffer( 6 ); + sprintf( res, "#%04x", LOWORD(str) ); return res; } + if (n == -1) + { + const WCHAR *end = str; + while (*end) end++; + n = end - str; + } if (n < 0) n = 0; - else if (n > 200) n = 200; - dst = res = gimme1(n * 5 + 7); + size = 12 + min( 300, n * 5 ); + dst = res = funcs.get_temp_buffer( n * 5 + 7 ); *dst++ = 'L'; *dst++ = '"'; - while (n-- > 0 && *src) + while (n-- > 0 && dst <= res + size - 10) { - WCHAR c = *src++; + WCHAR c = *str++; switch (c) { case '\n': *dst++ = '\\'; *dst++ = 'n'; break; case '\r': *dst++ = '\\'; *dst++ = 'r'; break; case '\t': *dst++ = '\\'; *dst++ = 't'; break; - case '"': *dst++ = '\\'; *dst++ = '"'; break; + case '"': *dst++ = '\\'; *dst++ = '"'; break; case '\\': *dst++ = '\\'; *dst++ = '\\'; break; default: if (c >= ' ' && c <= 126) @@ -200,37 +370,67 @@ const char *wine_dbgstr_wn(const WCHAR *src, int n) } } *dst++ = '"'; - if (*src) + if (n > 0) { *dst++ = '.'; *dst++ = '.'; *dst++ = '.'; } - *dst++ = '\0'; - release(dst); + *dst++ = 0; + funcs.release_temp_buffer( res, dst - res ); return res; } -const char *wine_dbgstr_longlong( unsigned long long ll ) + +/* default implementation of wine_dbg_vprintf */ +static int default_dbg_vprintf( const char *format, va_list args ) { - if (ll >> 32) return wine_dbg_sprintf( "%lx%08lx", (unsigned long)(ll >> 32), (unsigned long)ll ); - else return wine_dbg_sprintf( "%lx", (unsigned long)ll ); + char buffer[512]; + vsnprintf( buffer, sizeof(buffer), format, args ); + buffer[sizeof(buffer) - 1] = '\0'; + return DbgPrint( buffer ); } -/* varargs wrapper for __wine_dbg_vsprintf */ -const char *wine_dbg_sprintf( const char *format, ... ) + +/* default implementation of wine_dbg_vlog */ +static int default_dbg_vlog( enum __wine_debug_class cls, struct __wine_debug_channel *channel, + const char *file, const char *func, const int line, const char *format, va_list args ) { - char* buffer = gimme1(1024); - va_list ap; + int ret = 0; - va_start(ap, format); - release(buffer+vsnprintf(buffer, 1024, format, ap)); - va_end(ap); - - return buffer; + if (cls < sizeof(debug_classes)/sizeof(debug_classes[0])) + ret += wine_dbg_printf( "%s:", debug_classes[cls] ); + ret += wine_dbg_printf ( "(%s:%d) ", file, line ); + if (format) + ret += funcs.dbg_vprintf( format, args ); + return ret; } -const char *wine_dbgstr_w( const WCHAR *s ) +/* wrappers to use the function pointers */ + +const char *wine_dbgstr_an( const char * s, int n ) { - return wine_dbgstr_wn( s, -1 ); + return funcs.dbgstr_an(s, n); } + +const char *wine_dbgstr_wn( const WCHAR *s, int n ) +{ + return funcs.dbgstr_wn(s, n); +} + +void __wine_dbg_set_functions( const struct __wine_debug_functions *new_funcs, + struct __wine_debug_functions *old_funcs, size_t size ) +{ + if (old_funcs) memcpy( old_funcs, &funcs, min(sizeof(funcs),size) ); + if (new_funcs) memcpy( &funcs, new_funcs, min(sizeof(funcs),size) ); +} + +static struct __wine_debug_functions funcs = +{ + get_temp_buffer, + release_temp_buffer, + default_dbgstr_an, + default_dbgstr_wn, + default_dbg_vprintf, + default_dbg_vlog +};