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
22 #include "wine/port.h"
32 #ifdef HAVE_SYS_STAT_H
33 # include <sys/stat.h>
36 #include "wine/debug.h"
37 #include "wine/library.h"
39 struct __wine_debug_functions
41 char * (*get_temp_buffer
)( size_t n
);
42 void (*release_temp_buffer
)( char *buffer
, size_t n
);
43 const char * (*dbgstr_an
)( const char * s
, int n
);
44 const char * (*dbgstr_wn
)( const WCHAR
*s
, int n
);
45 int (*dbg_vprintf
)( const char *format
, va_list args
);
46 int (*dbg_vlog
)( enum __wine_debug_class cls
, struct __wine_debug_channel
*channel
,
47 const char *function
, const char *format
, va_list args
);
50 static const char * const debug_classes
[] = { "fixme", "err", "warn", "trace" };
52 #define MAX_DEBUG_OPTIONS 256
54 static unsigned char default_flags
= (1 << __WINE_DBCL_ERR
) | (1 << __WINE_DBCL_FIXME
);
55 static int nb_debug_options
= -1;
56 static struct __wine_debug_channel debug_options
[MAX_DEBUG_OPTIONS
];
58 static struct __wine_debug_functions funcs
;
60 static void debug_init(void);
62 static int cmp_name( const void *p1
, const void *p2
)
64 const char *name
= p1
;
65 const struct __wine_debug_channel
*chan
= p2
;
66 return strcmp( name
, chan
->name
);
69 /* get the flags to use for a given channel, possibly setting them too in case of lazy init */
70 unsigned char __wine_dbg_get_channel_flags_obsolete( struct __wine_debug_channel
*channel
)
72 if (nb_debug_options
== -1) debug_init();
76 struct __wine_debug_channel
*opt
= bsearch( channel
->name
, debug_options
, nb_debug_options
,
77 sizeof(debug_options
[0]), cmp_name
);
78 if (opt
) return opt
->flags
;
80 /* no option for this channel */
81 if (channel
->flags
& (1 << __WINE_DBCL_INIT
)) channel
->flags
= default_flags
;
85 /* set the flags to use for a given channel; return 0 if the channel is not available to set */
86 int __wine_dbg_set_channel_flags_obsolete( struct __wine_debug_channel
*channel
,
87 unsigned char set
, unsigned char clear
)
89 if (nb_debug_options
== -1) debug_init();
93 struct __wine_debug_channel
*opt
= bsearch( channel
->name
, debug_options
, nb_debug_options
,
94 sizeof(debug_options
[0]), cmp_name
);
97 opt
->flags
= (opt
->flags
& ~clear
) | set
;
104 /* add a new debug option at the end of the option list */
105 static void add_option( const char *name
, unsigned char set
, unsigned char clear
)
107 int min
= 0, max
= nb_debug_options
- 1, pos
, res
;
109 if (!name
[0]) /* "all" option */
111 default_flags
= (default_flags
& ~clear
) | set
;
114 if (strlen(name
) >= sizeof(debug_options
[0].name
)) return;
118 pos
= (min
+ max
) / 2;
119 res
= strcmp( name
, debug_options
[pos
].name
);
122 debug_options
[pos
].flags
= (debug_options
[pos
].flags
& ~clear
) | set
;
125 if (res
< 0) max
= pos
- 1;
128 if (nb_debug_options
>= MAX_DEBUG_OPTIONS
) return;
131 if (pos
< nb_debug_options
) memmove( &debug_options
[pos
+ 1], &debug_options
[pos
],
132 (nb_debug_options
- pos
) * sizeof(debug_options
[0]) );
133 strcpy( debug_options
[pos
].name
, name
);
134 debug_options
[pos
].flags
= (default_flags
& ~clear
) | set
;
138 /* parse a set of debugging option specifications and add them to the option list */
139 static void parse_options( const char *str
)
141 char *opt
, *next
, *options
;
144 if (!(options
= strdup(str
))) return;
145 for (opt
= options
; opt
; opt
= next
)
148 unsigned char set
= 0, clear
= 0;
150 if ((next
= strchr( opt
, ',' ))) *next
++ = 0;
152 p
= opt
+ strcspn( opt
, "+-" );
153 if (!p
[0]) p
= opt
; /* assume it's a debug channel name */
157 for (i
= 0; i
< ARRAY_SIZE(debug_classes
); i
++)
159 int len
= strlen(debug_classes
[i
]);
160 if (len
!= (p
- opt
)) continue;
161 if (!memcmp( opt
, debug_classes
[i
], len
)) /* found it */
163 if (*p
== '+') set
|= 1 << i
;
164 else clear
|= 1 << i
;
168 if (i
== ARRAY_SIZE(debug_classes
)) /* bad class name, skip it */
173 if (*p
== '-') clear
= ~0;
176 if (*p
== '+' || *p
== '-') p
++;
179 if (!strcmp( p
, "all" ))
180 default_flags
= (default_flags
& ~clear
) | set
;
182 add_option( p
, set
, clear
);
188 /* print the usage message */
189 static void debug_usage(void)
191 static const char usage
[] =
192 "Syntax of the WINEDEBUG variable:\n"
193 " WINEDEBUG=[class]+xxx,[class]-yyy,...\n\n"
194 "Example: WINEDEBUG=+all,warn-heap\n"
195 " turns on all messages except warning heap messages\n"
196 "Available message classes: err, warn, fixme, trace\n";
197 write( 2, usage
, sizeof(usage
) - 1 );
202 /* initialize all options at startup */
203 static void debug_init(void)
206 struct stat st1
, st2
;
208 if (nb_debug_options
!= -1) return; /* already initialized */
209 nb_debug_options
= 0;
211 /* check for stderr pointing to /dev/null */
212 if (!fstat( 2, &st1
) && S_ISCHR(st1
.st_mode
) &&
213 !stat( "/dev/null", &st2
) && S_ISCHR(st2
.st_mode
) &&
214 st1
.st_rdev
== st2
.st_rdev
)
219 if ((wine_debug
= getenv("WINEDEBUG")))
221 if (!strcmp( wine_debug
, "help" )) debug_usage();
222 parse_options( wine_debug
);
226 /* varargs wrapper for funcs.dbg_vprintf */
227 int wine_dbg_printf_obsolete( const char *format
, ... )
232 va_start(valist
, format
);
233 ret
= funcs
.dbg_vprintf( format
, valist
);
238 /* printf with temp buffer allocation */
239 const char *wine_dbg_sprintf_obsolete( const char *format
, ... )
241 static const int max_size
= 200;
246 va_start(valist
, format
);
247 ret
= funcs
.get_temp_buffer( max_size
);
248 len
= vsnprintf( ret
, max_size
, format
, valist
);
249 if (len
== -1 || len
>= max_size
) ret
[max_size
-1] = 0;
250 else funcs
.release_temp_buffer( ret
, len
+ 1 );
256 /* varargs wrapper for funcs.dbg_vlog */
257 int wine_dbg_log_obsolete( enum __wine_debug_class cls
, struct __wine_debug_channel
*channel
,
258 const char *func
, const char *format
, ... )
263 if (!(__wine_dbg_get_channel_flags_obsolete( channel
) & (1 << cls
))) return -1;
265 va_start(valist
, format
);
266 ret
= funcs
.dbg_vlog( cls
, channel
, func
, format
, valist
);
272 /* allocate some tmp string space */
273 /* FIXME: this is not 100% thread-safe */
274 static char *get_temp_buffer( size_t size
)
276 static char *list
[32];
281 idx
= pos
++ % ARRAY_SIZE(list
);
282 if ((ret
= realloc( list
[idx
], size
))) list
[idx
] = ret
;
287 /* release unused part of the buffer */
288 static void release_temp_buffer( char *buffer
, size_t size
)
290 /* don't bother doing anything */
294 /* default implementation of wine_dbgstr_an */
295 static const char *default_dbgstr_an( const char *str
, int n
)
297 static const char hex
[16] = "0123456789abcdef";
301 if (!((ULONG_PTR
)str
>> 16))
303 if (!str
) return "(null)";
304 res
= funcs
.get_temp_buffer( 6 );
305 sprintf( res
, "#%04x", LOWORD(str
) );
308 if (n
== -1) n
= strlen(str
);
310 size
= 10 + min( 300, n
* 4 );
311 dst
= res
= funcs
.get_temp_buffer( size
);
313 while (n
-- > 0 && dst
<= res
+ size
- 9)
315 unsigned char c
= *str
++;
318 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
319 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
320 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
321 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
322 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
324 if (c
>= ' ' && c
<= 126)
330 *dst
++ = hex
[(c
>> 4) & 0x0f];
331 *dst
++ = hex
[c
& 0x0f];
343 funcs
.release_temp_buffer( res
, dst
- res
);
348 /* default implementation of wine_dbgstr_wn */
349 static const char *default_dbgstr_wn( const WCHAR
*str
, int n
)
354 if (!((ULONG_PTR
)str
>> 16))
356 if (!str
) return "(null)";
357 res
= funcs
.get_temp_buffer( 6 );
358 sprintf( res
, "#%04x", LOWORD(str
) );
363 const WCHAR
*end
= str
;
368 size
= 12 + min( 300, n
* 5 );
369 dst
= res
= funcs
.get_temp_buffer( size
);
372 while (n
-- > 0 && dst
<= res
+ size
- 10)
377 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
378 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
379 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
380 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
381 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
383 if (c
>= ' ' && c
<= 126)
388 sprintf(dst
,"%04x",c
);
401 funcs
.release_temp_buffer( res
, dst
- res
);
406 /* default implementation of wine_dbg_vprintf */
407 static int default_dbg_vprintf( const char *format
, va_list args
)
409 return vfprintf( stderr
, format
, args
);
413 /* default implementation of wine_dbg_vlog */
414 static int default_dbg_vlog( enum __wine_debug_class cls
, struct __wine_debug_channel
*channel
,
415 const char *func
, const char *format
, va_list args
)
419 if (cls
< ARRAY_SIZE(debug_classes
))
420 ret
+= wine_dbg_printf_obsolete( "%s:%s:%s ", debug_classes
[cls
], channel
->name
, func
);
422 ret
+= funcs
.dbg_vprintf( format
, args
);
426 /* wrappers to use the function pointers */
428 const char *wine_dbgstr_an_obsolete( const char * s
, int n
)
430 return funcs
.dbgstr_an(s
, n
);
433 const char *wine_dbgstr_wn_obsolete( const WCHAR
*s
, int n
)
435 return funcs
.dbgstr_wn(s
, n
);
438 void __wine_dbg_set_functions_obsolete( const struct __wine_debug_functions
*new_funcs
,
439 struct __wine_debug_functions
*old_funcs
, size_t size
)
441 if (old_funcs
) memcpy( old_funcs
, &funcs
, min(sizeof(funcs
),size
) );
442 if (new_funcs
) memcpy( &funcs
, new_funcs
, min(sizeof(funcs
),size
) );
445 static struct __wine_debug_functions funcs
=
455 __ASM_OBSOLETE(__wine_dbg_get_channel_flags
);
456 __ASM_OBSOLETE(__wine_dbg_set_channel_flags
);
457 __ASM_OBSOLETE(__wine_dbg_set_functions
);
458 __ASM_OBSOLETE(wine_dbg_log
);
459 __ASM_OBSOLETE(wine_dbg_printf
);
460 __ASM_OBSOLETE(wine_dbg_sprintf
);
461 __ASM_OBSOLETE(wine_dbgstr_an
);
462 __ASM_OBSOLETE(wine_dbgstr_wn
);
464 #endif /* __ASM_OBSOLETE */