ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

debug.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.