Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendebug.c
Go to the documentation of this file.
00001 /* 00002 * Management of the debugging channels 00003 * 00004 * Copyright 2000 Alexandre Julliard 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #include "wine/config.h" 00022 #include "wine/port.h" 00023 00024 #include <stdlib.h> 00025 #include <stdio.h> 00026 #include <stdarg.h> 00027 #include <string.h> 00028 #include <ctype.h> 00029 #include <excpt.h> 00030 00031 #define WIN32_NO_STATUS 00032 #include "wine/debug.h" 00033 #include "wine/library.h" 00034 00035 #include <rtlfuncs.h> 00036 #include <cmfuncs.h> 00037 00038 ULONG 00039 NTAPI 00040 vDbgPrintExWithPrefix( 00041 IN LPCSTR Prefix, 00042 IN ULONG ComponentId, 00043 IN ULONG Level, 00044 IN LPCSTR Format, 00045 IN va_list ap); 00046 00047 00048 static const char * const debug_classes[] = { "fixme", "err", "warn", "trace" }; 00049 00050 #define MAX_DEBUG_OPTIONS 256 00051 00052 static unsigned char default_flags = (1 << __WINE_DBCL_ERR) | (1 << __WINE_DBCL_FIXME); 00053 static int nb_debug_options = -1; 00054 static struct __wine_debug_channel debug_options[MAX_DEBUG_OPTIONS]; 00055 00056 static struct __wine_debug_functions funcs; 00057 00058 static void debug_init(void); 00059 00060 static int __cdecl cmp_name( const void *p1, const void *p2 ) 00061 { 00062 const char *name = p1; 00063 const struct __wine_debug_channel *chan = p2; 00064 return strcmp( name, chan->name ); 00065 } 00066 00067 /* get the flags to use for a given channel, possibly setting them too in case of lazy init */ 00068 unsigned char __wine_dbg_get_channel_flags( struct __wine_debug_channel *channel ) 00069 { 00070 if (nb_debug_options == -1) debug_init(); 00071 00072 if (nb_debug_options) 00073 { 00074 struct __wine_debug_channel *opt = bsearch( channel->name, debug_options, nb_debug_options, 00075 sizeof(debug_options[0]), cmp_name ); 00076 if (opt) return opt->flags; 00077 } 00078 /* no option for this channel */ 00079 if (channel->flags & (1 << __WINE_DBCL_INIT)) channel->flags = default_flags; 00080 return default_flags; 00081 } 00082 00083 /* set the flags to use for a given channel; return 0 if the channel is not available to set */ 00084 int __wine_dbg_set_channel_flags( struct __wine_debug_channel *channel, 00085 unsigned char set, unsigned char clear ) 00086 { 00087 if (nb_debug_options == -1) debug_init(); 00088 00089 if (nb_debug_options) 00090 { 00091 struct __wine_debug_channel *opt = bsearch( channel->name, debug_options, nb_debug_options, 00092 sizeof(debug_options[0]), cmp_name ); 00093 if (opt) 00094 { 00095 opt->flags = (opt->flags & ~clear) | set; 00096 return 1; 00097 } 00098 } 00099 return 0; 00100 } 00101 00102 /* add a new debug option at the end of the option list */ 00103 static void add_option( const char *name, unsigned char set, unsigned char clear ) 00104 { 00105 int min = 0, max = nb_debug_options - 1, pos, res; 00106 00107 if (!name[0]) /* "all" option */ 00108 { 00109 default_flags = (default_flags & ~clear) | set; 00110 return; 00111 } 00112 if (strlen(name) >= sizeof(debug_options[0].name)) return; 00113 00114 while (min <= max) 00115 { 00116 pos = (min + max) / 2; 00117 res = strcmp( name, debug_options[pos].name ); 00118 if (!res) 00119 { 00120 debug_options[pos].flags = (debug_options[pos].flags & ~clear) | set; 00121 return; 00122 } 00123 if (res < 0) max = pos - 1; 00124 else min = pos + 1; 00125 } 00126 if (nb_debug_options >= MAX_DEBUG_OPTIONS) return; 00127 00128 pos = min; 00129 if (pos < nb_debug_options) memmove( &debug_options[pos + 1], &debug_options[pos], 00130 (nb_debug_options - pos) * sizeof(debug_options[0]) ); 00131 strcpy( debug_options[pos].name, name ); 00132 debug_options[pos].flags = (default_flags & ~clear) | set; 00133 nb_debug_options++; 00134 } 00135 00136 /* parse a set of debugging option specifications and add them to the option list */ 00137 static void parse_options( const char *str ) 00138 { 00139 char *opt, *next, *options; 00140 unsigned int i; 00141 00142 if (!(options = _strdup(str))) return; 00143 for (opt = options; opt; opt = next) 00144 { 00145 const char *p; 00146 unsigned char set = 0, clear = 0; 00147 00148 if ((next = strchr( opt, ',' ))) *next++ = 0; 00149 00150 p = opt + strcspn( opt, "+-" ); 00151 if (!p[0]) p = opt; /* assume it's a debug channel name */ 00152 00153 if (p > opt) 00154 { 00155 for (i = 0; i < sizeof(debug_classes)/sizeof(debug_classes[0]); i++) 00156 { 00157 int len = strlen(debug_classes[i]); 00158 if (len != (p - opt)) continue; 00159 if (!memcmp( opt, debug_classes[i], len )) /* found it */ 00160 { 00161 if (*p == '+') set |= 1 << i; 00162 else clear |= 1 << i; 00163 break; 00164 } 00165 } 00166 if (i == sizeof(debug_classes)/sizeof(debug_classes[0])) /* bad class name, skip it */ 00167 continue; 00168 } 00169 else 00170 { 00171 if (*p == '-') clear = ~0; 00172 else set = ~0; 00173 } 00174 if (*p == '+' || *p == '-') p++; 00175 if (!p[0]) continue; 00176 00177 if (!strcmp( p, "all" )) 00178 default_flags = (default_flags & ~clear) | set; 00179 else 00180 add_option( p, set, clear ); 00181 } 00182 free( options ); 00183 } 00184 00185 /* initialize all options at startup */ 00186 static void debug_init(void) 00187 { 00188 char *wine_debug; 00189 DWORD dwLength; 00190 /* GetEnvironmentVariableA will change LastError! */ 00191 DWORD LastError = GetLastError(); 00192 00193 if (nb_debug_options != -1) return; /* already initialized */ 00194 nb_debug_options = 0; 00195 00196 dwLength = GetEnvironmentVariableA("DEBUGCHANNEL", NULL, 0); 00197 if (dwLength) 00198 { 00199 wine_debug = malloc(dwLength); 00200 if (wine_debug) 00201 { 00202 if (GetEnvironmentVariableA("DEBUGCHANNEL", wine_debug, dwLength) < dwLength) 00203 parse_options(wine_debug); 00204 free(wine_debug); 00205 } 00206 } 00207 SetLastError(LastError); 00208 } 00209 00210 /* varargs wrapper for funcs.dbg_vprintf */ 00211 int wine_dbg_printf( const char *format, ... ) 00212 { 00213 int ret; 00214 va_list valist; 00215 00216 va_start(valist, format); 00217 ret = funcs.dbg_vprintf( format, valist ); 00218 va_end(valist); 00219 return ret; 00220 } 00221 00222 /* printf with temp buffer allocation */ 00223 const char *wine_dbg_sprintf( const char *format, ... ) 00224 { 00225 static const int max_size = 200; 00226 char *ret; 00227 int len; 00228 va_list valist; 00229 00230 va_start(valist, format); 00231 ret = funcs.get_temp_buffer( max_size ); 00232 len = vsnprintf( ret, max_size, format, valist ); 00233 if (len == -1 || len >= max_size) ret[max_size-1] = 0; 00234 else funcs.release_temp_buffer( ret, len + 1 ); 00235 va_end(valist); 00236 return ret; 00237 } 00238 00239 00240 /* varargs wrapper for funcs.dbg_vlog */ 00241 int wine_dbg_log( enum __wine_debug_class cls, struct __wine_debug_channel *channel, 00242 const char *file, const char *func, const int line, const char *format, ... ) 00243 { 00244 int ret; 00245 va_list valist; 00246 00247 if (!(__wine_dbg_get_channel_flags( channel ) & (1 << cls))) return -1; 00248 00249 va_start(valist, format); 00250 ret = funcs.dbg_vlog( cls, channel, file, func, line, format, valist ); 00251 va_end(valist); 00252 return ret; 00253 } 00254 00255 00256 /* allocate some tmp string space */ 00257 /* FIXME: this is not 100% thread-safe */ 00258 static char *get_temp_buffer( size_t size ) 00259 { 00260 static char *list[32]; 00261 static LONG pos; 00262 char *ret; 00263 int idx; 00264 00265 idx = interlocked_xchg_add( &pos, 1 ) % (sizeof(list)/sizeof(list[0])); 00266 if ((ret = realloc( list[idx], size ))) list[idx] = ret; 00267 return ret; 00268 } 00269 00270 00271 /* release unused part of the buffer */ 00272 static void release_temp_buffer( char *buffer, size_t size ) 00273 { 00274 /* don't bother doing anything */ 00275 } 00276 00277 00278 /* default implementation of wine_dbgstr_an */ 00279 static const char *default_dbgstr_an( const char *str, int n ) 00280 { 00281 static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 00282 char *dst, *res; 00283 size_t size; 00284 00285 if (!((ULONG_PTR)str >> 16)) 00286 { 00287 if (!str) return "(null)"; 00288 res = funcs.get_temp_buffer( 6 ); 00289 sprintf( res, "#%04x", LOWORD(str) ); 00290 return res; 00291 } 00292 if (n == -1) n = strlen(str); 00293 if (n < 0) n = 0; 00294 size = 10 + min( 300, n * 4 ); 00295 dst = res = funcs.get_temp_buffer( size ); 00296 *dst++ = '"'; 00297 while (n-- > 0 && dst <= res + size - 9) 00298 { 00299 unsigned char c = *str++; 00300 switch (c) 00301 { 00302 case '\n': *dst++ = '\\'; *dst++ = 'n'; break; 00303 case '\r': *dst++ = '\\'; *dst++ = 'r'; break; 00304 case '\t': *dst++ = '\\'; *dst++ = 't'; break; 00305 case '"': *dst++ = '\\'; *dst++ = '"'; break; 00306 case '\\': *dst++ = '\\'; *dst++ = '\\'; break; 00307 default: 00308 if (c >= ' ' && c <= 126) 00309 *dst++ = c; 00310 else 00311 { 00312 *dst++ = '\\'; 00313 *dst++ = 'x'; 00314 *dst++ = hex[(c >> 4) & 0x0f]; 00315 *dst++ = hex[c & 0x0f]; 00316 } 00317 } 00318 } 00319 *dst++ = '"'; 00320 if (n > 0) 00321 { 00322 *dst++ = '.'; 00323 *dst++ = '.'; 00324 *dst++ = '.'; 00325 } 00326 *dst++ = 0; 00327 funcs.release_temp_buffer( res, dst - res ); 00328 return res; 00329 } 00330 00331 00332 /* default implementation of wine_dbgstr_wn */ 00333 static const char *default_dbgstr_wn( const WCHAR *str, int n ) 00334 { 00335 char *dst, *res; 00336 size_t size; 00337 00338 if (!((ULONG_PTR)str >> 16)) 00339 { 00340 if (!str) return "(null)"; 00341 res = funcs.get_temp_buffer( 6 ); 00342 sprintf( res, "#%04x", LOWORD(str) ); 00343 return res; 00344 } 00345 if (n == -1) 00346 { 00347 const WCHAR *end = str; 00348 while (*end) end++; 00349 n = end - str; 00350 } 00351 if (n < 0) n = 0; 00352 size = 12 + min( 300, n * 5 ); 00353 dst = res = funcs.get_temp_buffer( n * 5 + 7 ); 00354 *dst++ = 'L'; 00355 *dst++ = '"'; 00356 while (n-- > 0 && dst <= res + size - 10) 00357 { 00358 WCHAR c = *str++; 00359 switch (c) 00360 { 00361 case '\n': *dst++ = '\\'; *dst++ = 'n'; break; 00362 case '\r': *dst++ = '\\'; *dst++ = 'r'; break; 00363 case '\t': *dst++ = '\\'; *dst++ = 't'; break; 00364 case '"': *dst++ = '\\'; *dst++ = '"'; break; 00365 case '\\': *dst++ = '\\'; *dst++ = '\\'; break; 00366 default: 00367 if (c >= ' ' && c <= 126) 00368 *dst++ = c; 00369 else 00370 { 00371 *dst++ = '\\'; 00372 sprintf(dst,"%04x",c); 00373 dst+=4; 00374 } 00375 } 00376 } 00377 *dst++ = '"'; 00378 if (n > 0) 00379 { 00380 *dst++ = '.'; 00381 *dst++ = '.'; 00382 *dst++ = '.'; 00383 } 00384 *dst++ = 0; 00385 funcs.release_temp_buffer( res, dst - res ); 00386 return res; 00387 } 00388 00389 00390 /* default implementation of wine_dbg_vprintf */ 00391 static int default_dbg_vprintf( const char *format, va_list args ) 00392 { 00393 return vDbgPrintExWithPrefix("", -1, 0, format, args); 00394 } 00395 00396 00397 /* default implementation of wine_dbg_vlog */ 00398 static int default_dbg_vlog( enum __wine_debug_class cls, struct __wine_debug_channel *channel, 00399 const char *file, const char *func, const int line, const char *format, va_list args ) 00400 { 00401 int ret = 0; 00402 00403 if (cls < sizeof(debug_classes)/sizeof(debug_classes[0])) 00404 ret += wine_dbg_printf( "%s:", debug_classes[cls] ); 00405 ret += wine_dbg_printf ( "(%s:%d) ", file, line ); 00406 if (format) 00407 ret += funcs.dbg_vprintf( format, args ); 00408 return ret; 00409 } 00410 00411 /* wrappers to use the function pointers */ 00412 00413 const char *wine_dbgstr_an( const char * s, int n ) 00414 { 00415 return funcs.dbgstr_an(s, n); 00416 } 00417 00418 const char *wine_dbgstr_wn( const WCHAR *s, int n ) 00419 { 00420 return funcs.dbgstr_wn(s, n); 00421 } 00422 00423 void __wine_dbg_set_functions( const struct __wine_debug_functions *new_funcs, 00424 struct __wine_debug_functions *old_funcs, size_t size ) 00425 { 00426 if (old_funcs) memcpy( old_funcs, &funcs, min(sizeof(funcs),size) ); 00427 if (new_funcs) memcpy( &funcs, new_funcs, min(sizeof(funcs),size) ); 00428 } 00429 00430 static struct __wine_debug_functions funcs = 00431 { 00432 get_temp_buffer, 00433 release_temp_buffer, 00434 default_dbgstr_an, 00435 default_dbgstr_wn, 00436 default_dbg_vprintf, 00437 default_dbg_vlog 00438 }; Generated on Sat May 26 2012 04:16:28 for ReactOS by
1.7.6.1
|