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 *opt
, *next
, *options
;
149 if (!(options
= strdup(str
))) return -1;
150 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
= opt
; /* assume it's a debug channel name */
162 for (i
= 0; i
< sizeof(debug_classes
)/sizeof(debug_classes
[0]); i
++)
164 int len
= strlen(debug_classes
[i
]);
165 if (len
!= (p
- opt
)) continue;
166 if (!memcmp( opt
, debug_classes
[i
], len
)) /* found it */
168 if (*p
== '+') set
|= 1 << i
;
169 else clear
|= 1 << i
;
173 if (i
== sizeof(debug_classes
)/sizeof(debug_classes
[0])) /* bad class name, skip it */
181 if (*p
== '-') clear
= ~0;
184 if (*p
== '+' || *p
== '-') p
++;
190 if (!strcmp( p
, "all" )) p
= ""; /* empty string means all */
191 wine_dbg_add_option( p
, set
, clear
);
197 /* varargs wrapper for __wine_dbg_vprintf */
198 int wine_dbg_printf( const char *format
, ... )
203 va_start(valist
, format
);
204 ret
= __wine_dbg_vprintf( format
, valist
);
210 /* varargs wrapper for __wine_dbg_vsprintf */
211 const char *wine_dbg_sprintf( const char *format
, ... )
216 va_start(valist
, format
);
217 ret
= __wine_dbg_vsprintf( format
, valist
);
223 /* varargs wrapper for __wine_dbg_vlog */
224 int wine_dbg_log( unsigned int cls
, const char *channel
, const char *func
, const char *format
, ... )
229 va_start(valist
, format
);
230 ret
= __wine_dbg_vlog( cls
, channel
, func
, format
, valist
);
236 /* allocate some tmp string space */
237 /* FIXME: this is not 100% thread-safe */
238 static char *get_tmp_space( int size
)
240 static char *list
[32];
245 idx
= interlocked_xchg_add( &pos
, 1 ) % (sizeof(list
)/sizeof(list
[0]));
246 if ((ret
= realloc( list
[idx
], size
))) list
[idx
] = ret
;
251 /* default implementation of wine_dbgstr_an */
252 static const char *default_dbgstr_an( const char *str
, int n
)
258 if (!str
) return "(null)";
259 res
= get_tmp_space( 6 );
260 sprintf( res
, "#%04x", LOWORD(str
) );
263 if (n
== -1) n
= strlen(str
);
265 else if (n
> 200) n
= 200;
266 dst
= res
= get_tmp_space( n
* 4 + 6 );
270 unsigned char c
= *str
++;
273 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
274 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
275 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
276 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
277 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
279 if (c
>= ' ' && c
<= 126)
284 *dst
++ = '0' + ((c
>> 6) & 7);
285 *dst
++ = '0' + ((c
>> 3) & 7);
286 *dst
++ = '0' + ((c
>> 0) & 7);
302 /* default implementation of wine_dbgstr_wn */
303 static const char *default_dbgstr_wn( const WCHAR
*str
, int n
)
309 if (!str
) return "(null)";
310 res
= get_tmp_space( 6 );
311 sprintf( res
, "#%04x", LOWORD(str
) );
314 if (n
== -1) n
= strlenW(str
);
316 else if (n
> 200) n
= 200;
317 dst
= res
= get_tmp_space( n
* 5 + 7 );
325 case '\n': *dst
++ = '\\'; *dst
++ = 'n'; break;
326 case '\r': *dst
++ = '\\'; *dst
++ = 'r'; break;
327 case '\t': *dst
++ = '\\'; *dst
++ = 't'; break;
328 case '"': *dst
++ = '\\'; *dst
++ = '"'; break;
329 case '\\': *dst
++ = '\\'; *dst
++ = '\\'; break;
331 if (c
>= ' ' && c
<= 126)
336 sprintf(dst
,"%04x",c
);
353 /* default implementation of wine_dbg_vsprintf */
354 static const char *default_dbg_vsprintf( const char *format
, va_list args
)
356 static const int max_size
= 200;
358 char *res
= get_tmp_space( max_size
);
359 int len
= vsnprintf( res
, max_size
, format
, args
);
360 if (len
== -1 || len
>= max_size
) res
[max_size
-1] = 0;
364 /* default implementation of wine_dbg_vprintf */
365 static int default_dbg_vprintf( const char *format
, va_list args
)
367 return vfprintf( stderr
, format
, args
);
371 /* default implementation of wine_dbg_vlog */
372 static int default_dbg_vlog( unsigned int cls
, const char *channel
, const char *func
,
373 const char *format
, va_list args
)
377 if (cls
< sizeof(debug_classes
)/sizeof(debug_classes
[0]))
378 ret
+= wine_dbg_printf( "%s:%s:%s ", debug_classes
[cls
], channel
+ 1, func
);
380 ret
+= __wine_dbg_vprintf( format
, args
);
385 /* exported function pointers so that debugging functions can be redirected at run-time */
387 const char * (*__wine_dbgstr_an
)( const char * s
, int n
) = default_dbgstr_an
;
388 const char * (*__wine_dbgstr_wn
)( const WCHAR
*s
, int n
) = default_dbgstr_wn
;
389 const char * (*__wine_dbg_vsprintf
)( const char *format
, va_list args
) = default_dbg_vsprintf
;
390 int (*__wine_dbg_vprintf
)( const char *format
, va_list args
) = default_dbg_vprintf
;
391 int (*__wine_dbg_vlog
)( unsigned int cls
, const char *channel
, const char *function
,
392 const char *format
, va_list args
) = default_dbg_vlog
;
394 /* wrappers to use the function pointers */
396 const char *wine_dbgstr_an( const char * s
, int n
)
398 return __wine_dbgstr_an(s
, n
);
401 const char *wine_dbgstr_wn( const WCHAR
*s
, int n
)
403 return __wine_dbgstr_wn(s
, n
);
406 const char *wine_dbgstr_a( const char *s
)
408 return __wine_dbgstr_an( s
, -1 );
411 const char *wine_dbgstr_w( const WCHAR
*s
)
413 return __wine_dbgstr_wn( s
, -1 );