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"
31 #include "wine/debug.h"
32 #include "wine/library.h"
33 #include "wine/unicode.h"
37 struct dll
*next
; /* linked list of dlls */
39 char * const *channels
; /* array of channels */
40 int nb_channels
; /* number of channels in array */
43 static struct dll
*first_dll
;
47 struct debug_option
*next
; /* next option in list */
48 unsigned char set
; /* bits to set */
49 unsigned char clear
; /* bits to clear */
50 char name
[14]; /* channel name, or empty for "all" */
53 static struct debug_option
*first_option
;
54 static struct debug_option
*last_option
;
56 static const char * const debug_classes
[] = { "fixme", "err", "warn", "trace" };
58 static int cmp_name( const void *p1
, const void *p2
)
60 const char *name
= p1
;
61 const char * const *chan
= p2
;
62 return strcmp( name
, *chan
+ 1 );
65 /* apply a debug option to the channels of a given dll */
66 static void apply_option( struct dll
*dll
, const struct debug_option
*opt
)
70 char **dbch
= bsearch( opt
->name
, dll
->channels
, dll
->nb_channels
,
71 sizeof(*dll
->channels
), cmp_name
);
72 if (dbch
) **dbch
= (**dbch
& ~opt
->clear
) | opt
->set
;
77 for (i
= 0; i
< dll
->nb_channels
; i
++)
78 dll
->channels
[i
][0] = (dll
->channels
[i
][0] & ~opt
->clear
) | opt
->set
;
82 /* register a new set of channels for a dll */
83 void *__wine_dbg_register( char * const *channels
, int nb
)
85 struct debug_option
*opt
= first_option
;
86 struct dll
*dll
= malloc( sizeof(*dll
) );
89 dll
->channels
= channels
;
90 dll
->nb_channels
= nb
;
92 if ((dll
->next
= first_dll
)) dll
->next
->prev
= dll
;
95 /* apply existing options to this dll */
98 apply_option( dll
, opt
);
106 /* unregister a set of channels; must pass the pointer obtained from wine_dbg_register */
107 void __wine_dbg_unregister( void *channel
)
109 struct dll
*dll
= channel
;
112 if (dll
->next
) dll
->next
->prev
= dll
->prev
;
113 if (dll
->prev
) dll
->prev
->next
= dll
->next
;
114 else first_dll
= dll
->next
;
120 /* add a new debug option at the end of the option list */
121 void wine_dbg_add_option( const char *name
, unsigned char set
, unsigned char clear
)
123 struct dll
*dll
= first_dll
;
124 struct debug_option
*opt
;
126 if (!(opt
= malloc( sizeof(*opt
) ))) return;
130 strncpy( opt
->name
, name
, sizeof(opt
->name
) );
131 opt
->name
[sizeof(opt
->name
)-1] = 0;
132 if (last_option
) last_option
->next
= opt
;
133 else first_option
= opt
;
136 /* apply option to all existing dlls */
139 apply_option( dll
, opt
);
144 /* parse a set of debugging option specifications and add them to the option list */
145 int wine_dbg_parse_options( const char *str
)
147 char *p
, *opt
, *next
, *options
;
150 if (!(options
= strdup(str
))) return -1;
151 for (opt
= options
; opt
; opt
= next
)
153 unsigned char set
= 0, clear
= 0;
155 if ((next
= strchr( opt
, ',' ))) *next
++ = 0;
157 p
= opt
+ strcspn( opt
, "+-" );
158 if (!p
[0] || !p
[1]) /* bad option, skip it */
166 for (i
= 0; i
< sizeof(debug_classes
)/sizeof(debug_classes
[0]); i
++)
168 int len
= strlen(debug_classes
[i
]);
169 if (len
!= (p
- opt
)) continue;
170 if (!memcmp( opt
, debug_classes
[i
], len
)) /* found it */
172 if (*p
== '+') set
|= 1 << i
;
173 else clear
|= 1 << i
;
177 if (i
== sizeof(debug_classes
)/sizeof(debug_classes
[0])) /* bad class name, skip it */
185 if (*p
== '+') set
= ~0;
189 if (!strcmp( p
, "all" )) p
= ""; /* empty string means all */
190 wine_dbg_add_option( p
, set
, clear
);
196 /* varargs wrapper for __wine_dbg_vprintf */
197 int wine_dbg_printf( const char *format
, ... )
202 va_start(valist
, format
);
203 ret
= __wine_dbg_vprintf( format
, valist
);
209 /* varargs wrapper for __wine_dbg_vlog */
210 int wine_dbg_log( int cls
, const char *channel
, const char *func
, const char *format
, ... )
215 va_start(valist
, format
);
216 ret
= __wine_dbg_vlog( cls
, channel
, func
, format
, valist
);
222 /* allocate some tmp string space */
223 /* FIXME: this is not 100% thread-safe */
224 static char *get_tmp_space( int size
)
226 static char *list
[32];
231 idx
= interlocked_xchg_add( &pos
, 1 ) % (sizeof(list
)/sizeof(list
[0]));
232 if ((ret
= realloc( list
[idx
], size
))) list
[idx
] = ret
;
237 /* default implementation of wine_dbgstr_an */
238 static const char *default_dbgstr_an( const char *str
, int n
)
244 if (!str
) return "(null)";
245 res
= get_tmp_space( 6 );
246 sprintf( res
, "#%04x", LOWORD(str
) );
249 if (n
== -1) n
= strlen(str
);
251 else if (n
> 200) n
= 200;
252 dst
= res
= get_tmp_space( n
* 4 + 6 );
256 unsigned char c
= *str
++;
259 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
260 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
261 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
262 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
263 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
265 if (c
>= ' ' && c
<= 126)
270 *dst
++ = '0' + ((c
>> 6) & 7);
271 *dst
++ = '0' + ((c
>> 3) & 7);
272 *dst
++ = '0' + ((c
>> 0) & 7);
288 /* default implementation of wine_dbgstr_wn */
289 static const char *default_dbgstr_wn( const WCHAR
*str
, int n
)
295 if (!str
) return "(null)";
296 res
= get_tmp_space( 6 );
297 sprintf( res
, "#%04x", LOWORD(str
) );
300 if (n
== -1) n
= strlenW(str
);
302 else if (n
> 200) n
= 200;
303 dst
= res
= get_tmp_space( n
* 5 + 7 );
311 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
312 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
313 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
314 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
315 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
317 if (c
>= ' ' && c
<= 126)
322 sprintf(dst
,"%04x",c
);
339 /* default implementation of wine_dbgstr_guid */
340 static const char *default_dbgstr_guid( const struct _GUID
*id
)
344 if (!id
) return "(null)";
345 if (!((int)id
>> 16))
347 str
= get_tmp_space( 12 );
348 sprintf( str
, "<guid-0x%04x>", (int)id
& 0xffff );
352 str
= get_tmp_space( 40 );
353 sprintf( str
, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
354 id
->Data1
, id
->Data2
, id
->Data3
,
355 id
->Data4
[0], id
->Data4
[1], id
->Data4
[2], id
->Data4
[3],
356 id
->Data4
[4], id
->Data4
[5], id
->Data4
[6], id
->Data4
[7] );
362 /* default implementation of wine_dbg_vprintf */
363 static int default_dbg_vprintf( const char *format
, va_list args
)
365 return vfprintf( stderr
, format
, args
);
369 /* default implementation of wine_dbg_vlog */
370 static int default_dbg_vlog( int cls
, const char *channel
, const char *func
,
371 const char *format
, va_list args
)
375 if (cls
< sizeof(debug_classes
)/sizeof(debug_classes
[0]))
376 ret
+= wine_dbg_printf( "%s:%s:%s ", debug_classes
[cls
], channel
+ 1, func
);
378 ret
+= __wine_dbg_vprintf( format
, args
);
383 /* exported function pointers so that debugging functions can be redirected at run-time */
385 const char * (*__wine_dbgstr_an
)( const char * s
, int n
) = default_dbgstr_an
;
386 const char * (*__wine_dbgstr_wn
)( const WCHAR
*s
, int n
) = default_dbgstr_wn
;
387 const char * (*__wine_dbgstr_guid
)( const struct _GUID
*id
) = default_dbgstr_guid
;
388 int (*__wine_dbg_vprintf
)( const char *format
, va_list args
) = default_dbg_vprintf
;
389 int (*__wine_dbg_vlog
)( int cls
, const char *channel
, const char *function
,
390 const char *format
, va_list args
) = default_dbg_vlog
;
392 /* wrappers to use the function pointers */
394 const char *wine_dbgstr_guid( const struct _GUID
*id
)
396 return __wine_dbgstr_guid(id
);
399 const char *wine_dbgstr_an( const char * s
, int n
)
401 return __wine_dbgstr_an(s
, n
);
404 const char *wine_dbgstr_wn( const WCHAR
*s
, int n
)
406 return __wine_dbgstr_wn(s
, n
);
409 const char *wine_dbgstr_a( const char *s
)
411 return __wine_dbgstr_an( s
, -1 );
414 const char *wine_dbgstr_w( const WCHAR
*s
)
416 return __wine_dbgstr_wn( s
, -1 );