2 * Management of the debugging channels
4 * Copyright 2000 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/config.h"
22 #include "wine/port.h"
31 #define WIN32_NO_STATUS
32 #include "wine/debug.h"
33 #include "wine/library.h"
40 vDbgPrintExWithPrefix(
48 static const char * const debug_classes
[] = { "fixme", "err", "warn", "trace" };
50 #define MAX_DEBUG_OPTIONS 256
52 static unsigned char default_flags
= (1 << __WINE_DBCL_ERR
) | (1 << __WINE_DBCL_FIXME
);
53 static int nb_debug_options
= -1;
54 static struct __wine_debug_channel debug_options
[MAX_DEBUG_OPTIONS
];
56 static struct __wine_debug_functions funcs
;
58 static void debug_init(void);
60 static int __cdecl
cmp_name( const void *p1
, const void *p2
)
62 const char *name
= p1
;
63 const struct __wine_debug_channel
*chan
= p2
;
64 return strcmp( name
, chan
->name
);
67 /* get the flags to use for a given channel, possibly setting them too in case of lazy init */
68 unsigned char __wine_dbg_get_channel_flags( struct __wine_debug_channel
*channel
)
70 if (nb_debug_options
== -1) debug_init();
74 struct __wine_debug_channel
*opt
= bsearch( channel
->name
, debug_options
, nb_debug_options
,
75 sizeof(debug_options
[0]), cmp_name
);
76 if (opt
) return opt
->flags
;
78 /* no option for this channel */
79 if (channel
->flags
& (1 << __WINE_DBCL_INIT
)) channel
->flags
= default_flags
;
83 /* set the flags to use for a given channel; return 0 if the channel is not available to set */
84 int __wine_dbg_set_channel_flags( struct __wine_debug_channel
*channel
,
85 unsigned char set
, unsigned char clear
)
87 if (nb_debug_options
== -1) debug_init();
91 struct __wine_debug_channel
*opt
= bsearch( channel
->name
, debug_options
, nb_debug_options
,
92 sizeof(debug_options
[0]), cmp_name
);
95 opt
->flags
= (opt
->flags
& ~clear
) | set
;
102 /* add a new debug option at the end of the option list */
103 static void add_option( const char *name
, unsigned char set
, unsigned char clear
)
105 int min
= 0, max
= nb_debug_options
- 1, pos
, res
;
107 if (!name
[0]) /* "all" option */
109 default_flags
= (default_flags
& ~clear
) | set
;
112 if (strlen(name
) >= sizeof(debug_options
[0].name
)) return;
116 pos
= (min
+ max
) / 2;
117 res
= strcmp( name
, debug_options
[pos
].name
);
120 debug_options
[pos
].flags
= (debug_options
[pos
].flags
& ~clear
) | set
;
123 if (res
< 0) max
= pos
- 1;
126 if (nb_debug_options
>= MAX_DEBUG_OPTIONS
) return;
129 if (pos
< nb_debug_options
) memmove( &debug_options
[pos
+ 1], &debug_options
[pos
],
130 (nb_debug_options
- pos
) * sizeof(debug_options
[0]) );
131 strcpy( debug_options
[pos
].name
, name
);
132 debug_options
[pos
].flags
= (default_flags
& ~clear
) | set
;
136 /* parse a set of debugging option specifications and add them to the option list */
137 static void parse_options( const char *str
)
139 char *opt
, *next
, *options
;
142 if (!(options
= _strdup(str
))) return;
143 for (opt
= options
; opt
; opt
= next
)
146 unsigned char set
= 0, clear
= 0;
148 if ((next
= strchr( opt
, ',' ))) *next
++ = 0;
150 p
= opt
+ strcspn( opt
, "+-" );
151 if (!p
[0]) p
= opt
; /* assume it's a debug channel name */
155 for (i
= 0; i
< sizeof(debug_classes
)/sizeof(debug_classes
[0]); i
++)
157 int len
= strlen(debug_classes
[i
]);
158 if (len
!= (p
- opt
)) continue;
159 if (!memcmp( opt
, debug_classes
[i
], len
)) /* found it */
161 if (*p
== '+') set
|= 1 << i
;
162 else clear
|= 1 << i
;
166 if (i
== sizeof(debug_classes
)/sizeof(debug_classes
[0])) /* bad class name, skip it */
171 if (*p
== '-') clear
= ~0;
174 if (*p
== '+' || *p
== '-') p
++;
177 if (!strcmp( p
, "all" ))
178 default_flags
= (default_flags
& ~clear
) | set
;
180 add_option( p
, set
, clear
);
185 /* initialize all options at startup */
186 static void debug_init(void)
190 /* GetEnvironmentVariableA will change LastError! */
191 DWORD LastError
= GetLastError();
193 if (nb_debug_options
!= -1) return; /* already initialized */
194 nb_debug_options
= 0;
196 dwLength
= GetEnvironmentVariableA("DEBUGCHANNEL", NULL
, 0);
199 wine_debug
= malloc(dwLength
);
202 if (GetEnvironmentVariableA("DEBUGCHANNEL", wine_debug
, dwLength
) < dwLength
)
203 parse_options(wine_debug
);
207 SetLastError(LastError
);
210 /* varargs wrapper for funcs.dbg_vprintf */
211 int wine_dbg_printf( const char *format
, ... )
216 va_start(valist
, format
);
217 ret
= funcs
.dbg_vprintf( format
, valist
);
222 /* printf with temp buffer allocation */
223 const char *wine_dbg_sprintf( const char *format
, ... )
225 static const int max_size
= 200;
230 va_start(valist
, format
);
231 ret
= funcs
.get_temp_buffer( max_size
);
232 len
= vsnprintf( ret
, max_size
, format
, valist
);
233 if (len
== -1 || len
>= max_size
) ret
[max_size
-1] = 0;
234 else funcs
.release_temp_buffer( ret
, len
+ 1 );
240 /* varargs wrapper for funcs.dbg_vlog */
241 int wine_dbg_log( enum __wine_debug_class cls
, struct __wine_debug_channel
*channel
,
242 const char *file
, const char *func
, const int line
, const char *format
, ... )
247 if (!(__wine_dbg_get_channel_flags( channel
) & (1 << cls
))) return -1;
249 va_start(valist
, format
);
250 ret
= funcs
.dbg_vlog( cls
, channel
, file
, func
, line
, format
, valist
);
256 /* allocate some tmp string space */
257 /* FIXME: this is not 100% thread-safe */
258 static char *get_temp_buffer( size_t size
)
260 static char *list
[32];
265 idx
= InterlockedExchangeAdd( &pos
, 1 ) % (sizeof(list
)/sizeof(list
[0]));
266 if ((ret
= realloc( list
[idx
], size
))) list
[idx
] = ret
;
271 /* release unused part of the buffer */
272 static void release_temp_buffer( char *buffer
, size_t size
)
274 /* don't bother doing anything */
278 /* default implementation of wine_dbgstr_an */
279 static const char *default_dbgstr_an( const char *str
, int n
)
281 static const char hex
[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
285 if (!((ULONG_PTR
)str
>> 16))
287 if (!str
) return "(null)";
288 res
= funcs
.get_temp_buffer( 6 );
289 sprintf( res
, "#%04x", LOWORD(str
) );
292 if (n
== -1) n
= strlen(str
);
294 size
= 10 + min( 300, n
* 4 );
295 dst
= res
= funcs
.get_temp_buffer( size
);
297 while (n
-- > 0 && dst
<= res
+ size
- 9)
299 unsigned char c
= *str
++;
302 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
303 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
304 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
305 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
306 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
308 if (c
>= ' ' && c
<= 126)
314 *dst
++ = hex
[(c
>> 4) & 0x0f];
315 *dst
++ = hex
[c
& 0x0f];
327 funcs
.release_temp_buffer( res
, dst
- res
);
332 /* default implementation of wine_dbgstr_wn */
333 static const char *default_dbgstr_wn( const WCHAR
*str
, int n
)
338 if (!((ULONG_PTR
)str
>> 16))
340 if (!str
) return "(null)";
341 res
= funcs
.get_temp_buffer( 6 );
342 sprintf( res
, "#%04x", LOWORD(str
) );
347 const WCHAR
*end
= str
;
352 size
= 12 + min( 300, n
* 5 );
353 dst
= res
= funcs
.get_temp_buffer( n
* 5 + 7 );
356 while (n
-- > 0 && dst
<= res
+ size
- 10)
361 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
362 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
363 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
364 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
365 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
367 if (c
>= ' ' && c
<= 126)
372 sprintf(dst
,"%04x",c
);
385 funcs
.release_temp_buffer( res
, dst
- res
);
390 /* default implementation of wine_dbg_vprintf */
391 static int default_dbg_vprintf( const char *format
, va_list args
)
393 return vDbgPrintExWithPrefix("", -1, 0, format
, args
);
397 /* default implementation of wine_dbg_vlog */
398 static int default_dbg_vlog( enum __wine_debug_class cls
, struct __wine_debug_channel
*channel
,
399 const char *file
, const char *func
, const int line
, const char *format
, va_list args
)
403 if (cls
< sizeof(debug_classes
)/sizeof(debug_classes
[0]))
404 ret
+= wine_dbg_printf( "%s:", debug_classes
[cls
] );
405 ret
+= wine_dbg_printf ( "(%s:%d) ", file
, line
);
407 ret
+= funcs
.dbg_vprintf( format
, args
);
411 /* wrappers to use the function pointers */
413 const char *wine_dbgstr_an( const char * s
, int n
)
415 return funcs
.dbgstr_an(s
, n
);
418 const char *wine_dbgstr_wn( const WCHAR
*s
, int n
)
420 return funcs
.dbgstr_wn(s
, n
);
423 void __wine_dbg_set_functions( const struct __wine_debug_functions
*new_funcs
,
424 struct __wine_debug_functions
*old_funcs
, size_t size
)
426 if (old_funcs
) memcpy( old_funcs
, &funcs
, min(sizeof(funcs
),size
) );
427 if (new_funcs
) memcpy( &funcs
, new_funcs
, min(sizeof(funcs
),size
) );
430 static struct __wine_debug_functions funcs
=