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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
30 #include "wine/debug.h"
31 #include "wine/library.h"
32 #include "wine/unicode.h"
36 struct dll
*next
; /* linked list of dlls */
38 char * const *channels
; /* array of channels */
39 int nb_channels
; /* number of channels in array */
42 static struct dll
*first_dll
;
46 struct debug_option
*next
; /* next option in list */
47 unsigned char set
; /* bits to set */
48 unsigned char clear
; /* bits to clear */
49 char name
[14]; /* channel name, or empty for "all" */
52 static struct debug_option
*first_option
;
53 static struct debug_option
*last_option
;
55 static const char * const debug_classes
[] = { "fixme", "err", "warn", "trace" };
57 static int cmp_name( const void *p1
, const void *p2
)
59 const char *name
= p1
;
60 const char * const *chan
= p2
;
61 return strcmp( name
, *chan
+ 1 );
64 /* apply a debug option to the channels of a given dll */
65 static void apply_option( struct dll
*dll
, const struct debug_option
*opt
)
69 char **dbch
= bsearch( opt
->name
, dll
->channels
, dll
->nb_channels
,
70 sizeof(*dll
->channels
), cmp_name
);
71 if (dbch
) **dbch
= (**dbch
& ~opt
->clear
) | opt
->set
;
76 for (i
= 0; i
< dll
->nb_channels
; i
++)
77 dll
->channels
[i
][0] = (dll
->channels
[i
][0] & ~opt
->clear
) | opt
->set
;
81 /* register a new set of channels for a dll */
82 void *__wine_dbg_register( char * const *channels
, int nb
)
84 struct debug_option
*opt
= first_option
;
85 struct dll
*dll
= malloc( sizeof(*dll
) );
88 dll
->channels
= channels
;
89 dll
->nb_channels
= nb
;
91 if ((dll
->next
= first_dll
)) dll
->next
->prev
= dll
;
94 /* apply existing options to this dll */
97 apply_option( dll
, opt
);
105 /* unregister a set of channels; must pass the pointer obtained from wine_dbg_register */
106 void __wine_dbg_unregister( void *channel
)
108 struct dll
*dll
= channel
;
111 if (dll
->next
) dll
->next
->prev
= dll
->prev
;
112 if (dll
->prev
) dll
->prev
->next
= dll
->next
;
113 else first_dll
= dll
->next
;
119 /* add a new debug option at the end of the option list */
120 void wine_dbg_add_option( const char *name
, unsigned char set
, unsigned char clear
)
122 struct dll
*dll
= first_dll
;
123 struct debug_option
*opt
;
125 if (!(opt
= malloc( sizeof(*opt
) ))) return;
129 strncpy( opt
->name
, name
, sizeof(opt
->name
) );
130 opt
->name
[sizeof(opt
->name
)-1] = 0;
131 if (last_option
) last_option
->next
= opt
;
132 else first_option
= opt
;
135 /* apply option to all existing dlls */
138 apply_option( dll
, opt
);
143 /* parse a set of debugging option specifications and add them to the option list */
144 int wine_dbg_parse_options( const char *str
)
146 char *p
, *opt
, *next
, *options
;
149 if (!(options
= strdup(str
))) return -1;
150 for (opt
= options
; opt
; opt
= next
)
152 unsigned char set
= 0, clear
= 0;
154 if ((next
= strchr( opt
, ',' ))) *next
++ = 0;
156 p
= opt
+ strcspn( opt
, "+-" );
157 if (!p
[0] || !p
[1]) /* bad option, skip it */
165 for (i
= 0; i
< sizeof(debug_classes
)/sizeof(debug_classes
[0]); i
++)
167 int len
= strlen(debug_classes
[i
]);
168 if (len
!= (p
- opt
)) continue;
169 if (!memcmp( opt
, debug_classes
[i
], len
)) /* found it */
171 if (*p
== '+') set
|= 1 << i
;
172 else clear
|= 1 << i
;
176 if (i
== sizeof(debug_classes
)/sizeof(debug_classes
[0])) /* bad class name, skip it */
184 if (*p
== '+') set
= ~0;
188 if (!strcmp( p
, "all" )) p
= ""; /* empty string means all */
189 wine_dbg_add_option( p
, set
, clear
);
195 /* varargs wrapper for __wine_dbg_vprintf */
196 int wine_dbg_printf( const char *format
, ... )
201 va_start(valist
, format
);
202 ret
= __wine_dbg_vprintf( format
, valist
);
208 /* varargs wrapper for __wine_dbg_vlog */
209 int wine_dbg_log( int cls
, const char *channel
, const char *func
, const char *format
, ... )
214 va_start(valist
, format
);
215 ret
= __wine_dbg_vlog( cls
, channel
, func
, format
, valist
);
221 /* allocate some tmp string space */
222 /* FIXME: this is not 100% thread-safe */
223 static char *get_tmp_space( int size
)
225 static char *list
[32];
230 idx
= interlocked_xchg_add( &pos
, 1 ) % (sizeof(list
)/sizeof(list
[0]));
231 if ((ret
= realloc( list
[idx
], size
))) list
[idx
] = ret
;
236 /* default implementation of wine_dbgstr_an */
237 static const char *default_dbgstr_an( const char *str
, int n
)
243 if (!str
) return "(null)";
244 res
= get_tmp_space( 6 );
245 sprintf( res
, "#%04x", LOWORD(str
) );
248 if (n
== -1) n
= strlen(str
);
250 else if (n
> 200) n
= 200;
251 dst
= res
= get_tmp_space( n
* 4 + 6 );
255 unsigned char c
= *str
++;
258 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
259 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
260 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
261 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
262 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
264 if (c
>= ' ' && c
<= 126)
269 *dst
++ = '0' + ((c
>> 6) & 7);
270 *dst
++ = '0' + ((c
>> 3) & 7);
271 *dst
++ = '0' + ((c
>> 0) & 7);
287 /* default implementation of wine_dbgstr_wn */
288 static const char *default_dbgstr_wn( const WCHAR
*str
, int n
)
294 if (!str
) return "(null)";
295 res
= get_tmp_space( 6 );
296 sprintf( res
, "#%04x", LOWORD(str
) );
299 if (n
== -1) n
= strlenW(str
);
301 else if (n
> 200) n
= 200;
302 dst
= res
= get_tmp_space( n
* 5 + 7 );
310 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
311 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
312 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
313 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
314 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
316 if (c
>= ' ' && c
<= 126)
321 sprintf(dst
,"%04x",c
);
338 /* default implementation of wine_dbgstr_guid */
339 static const char *default_dbgstr_guid( const struct _GUID
*id
)
343 if (!id
) return "(null)";
344 if (!((int)id
>> 16))
346 str
= get_tmp_space( 12 );
347 sprintf( str
, "<guid-0x%04x>", (int)id
& 0xffff );
351 str
= get_tmp_space( 40 );
352 sprintf( str
, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
353 id
->Data1
, id
->Data2
, id
->Data3
,
354 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
355 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
361 /* default implementation of wine_dbg_vprintf */
362 static int default_dbg_vprintf( const char *format
, va_list args
)
364 return vfprintf( stderr
, format
, args
);
368 /* default implementation of wine_dbg_vlog */
369 static int default_dbg_vlog( int cls
, const char *channel
, const char *func
,
370 const char *format
, va_list args
)
374 if (cls
< sizeof(debug_classes
)/sizeof(debug_classes
[0]))
375 ret
+= wine_dbg_printf( "%s:%s:%s ", debug_classes
[cls
], channel
+ 1, func
);
377 ret
+= __wine_dbg_vprintf( format
, args
);
382 /* exported function pointers so that debugging functions can be redirected at run-time */
384 const char * (*__wine_dbgstr_an
)( const char * s
, int n
) = default_dbgstr_an
;
385 const char * (*__wine_dbgstr_wn
)( const WCHAR
*s
, int n
) = default_dbgstr_wn
;
386 const char * (*__wine_dbgstr_guid
)( const struct _GUID
*id
) = default_dbgstr_guid
;
387 int (*__wine_dbg_vprintf
)( const char *format
, va_list args
) = default_dbg_vprintf
;
388 int (*__wine_dbg_vlog
)( int cls
, const char *channel
, const char *function
,
389 const char *format
, va_list args
) = default_dbg_vlog
;
391 /* wrappers to use the function pointers */
393 const char *wine_dbgstr_guid( const struct _GUID
*id
)
395 return __wine_dbgstr_guid(id
);
398 const char *wine_dbgstr_an( const char * s
, int n
)
400 return __wine_dbgstr_an(s
, n
);
403 const char *wine_dbgstr_wn( const WCHAR
*s
, int n
)
405 return __wine_dbgstr_wn(s
, n
);
408 const char *wine_dbgstr_a( const char *s
)
410 return __wine_dbgstr_an( s
, -1 );
413 const char *wine_dbgstr_w( const WCHAR
*s
)
415 return __wine_dbgstr_wn( s
, -1 );