wineps: Use the get_pagesize helper to look up the default pagesize.
[wine] / libs / wine / debug.c
1 /*
2  * Management of the debugging channels
3  *
4  * Copyright 2000 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <ctype.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32
33 #include "wine/debug.h"
34 #include "wine/library.h"
35
36 static const char * const debug_classes[] = { "fixme", "err", "warn", "trace" };
37
38 #define MAX_DEBUG_OPTIONS 256
39
40 static unsigned char default_flags = (1 << __WINE_DBCL_ERR) | (1 << __WINE_DBCL_FIXME);
41 static int nb_debug_options = -1;
42 static struct __wine_debug_channel debug_options[MAX_DEBUG_OPTIONS];
43
44 static struct __wine_debug_functions funcs;
45
46 static void debug_init(void);
47
48 static int cmp_name( const void *p1, const void *p2 )
49 {
50     const char *name = p1;
51     const struct __wine_debug_channel *chan = p2;
52     return strcmp( name, chan->name );
53 }
54
55 /* get the flags to use for a given channel, possibly setting them too in case of lazy init */
56 unsigned char __wine_dbg_get_channel_flags( struct __wine_debug_channel *channel )
57 {
58     if (nb_debug_options == -1) debug_init();
59
60     if (nb_debug_options)
61     {
62         struct __wine_debug_channel *opt = bsearch( channel->name, debug_options, nb_debug_options,
63                                                     sizeof(debug_options[0]), cmp_name );
64         if (opt) return opt->flags;
65     }
66     /* no option for this channel */
67     if (channel->flags & (1 << __WINE_DBCL_INIT)) channel->flags = default_flags;
68     return default_flags;
69 }
70
71 /* set the flags to use for a given channel; return 0 if the channel is not available to set */
72 int __wine_dbg_set_channel_flags( struct __wine_debug_channel *channel,
73                                   unsigned char set, unsigned char clear )
74 {
75     if (nb_debug_options == -1) debug_init();
76
77     if (nb_debug_options)
78     {
79         struct __wine_debug_channel *opt = bsearch( channel->name, debug_options, nb_debug_options,
80                                                     sizeof(debug_options[0]), cmp_name );
81         if (opt)
82         {
83             opt->flags = (opt->flags & ~clear) | set;
84             return 1;
85         }
86     }
87     return 0;
88 }
89
90 /* add a new debug option at the end of the option list */
91 static void add_option( const char *name, unsigned char set, unsigned char clear )
92 {
93     int min = 0, max = nb_debug_options - 1, pos, res;
94
95     if (!name[0])  /* "all" option */
96     {
97         default_flags = (default_flags & ~clear) | set;
98         return;
99     }
100     if (strlen(name) >= sizeof(debug_options[0].name)) return;
101
102     while (min <= max)
103     {
104         pos = (min + max) / 2;
105         res = strcmp( name, debug_options[pos].name );
106         if (!res)
107         {
108             debug_options[pos].flags = (debug_options[pos].flags & ~clear) | set;
109             return;
110         }
111         if (res < 0) max = pos - 1;
112         else min = pos + 1;
113     }
114     if (nb_debug_options >= MAX_DEBUG_OPTIONS) return;
115
116     pos = min;
117     if (pos < nb_debug_options) memmove( &debug_options[pos + 1], &debug_options[pos],
118                                          (nb_debug_options - pos) * sizeof(debug_options[0]) );
119     strcpy( debug_options[pos].name, name );
120     debug_options[pos].flags = (default_flags & ~clear) | set;
121     nb_debug_options++;
122 }
123
124 /* parse a set of debugging option specifications and add them to the option list */
125 static void parse_options( const char *str )
126 {
127     char *opt, *next, *options;
128     unsigned int i;
129
130     if (!(options = strdup(str))) return;
131     for (opt = options; opt; opt = next)
132     {
133         const char *p;
134         unsigned char set = 0, clear = 0;
135
136         if ((next = strchr( opt, ',' ))) *next++ = 0;
137
138         p = opt + strcspn( opt, "+-" );
139         if (!p[0]) p = opt;  /* assume it's a debug channel name */
140
141         if (p > opt)
142         {
143             for (i = 0; i < sizeof(debug_classes)/sizeof(debug_classes[0]); i++)
144             {
145                 int len = strlen(debug_classes[i]);
146                 if (len != (p - opt)) continue;
147                 if (!memcmp( opt, debug_classes[i], len ))  /* found it */
148                 {
149                     if (*p == '+') set |= 1 << i;
150                     else clear |= 1 << i;
151                     break;
152                 }
153             }
154             if (i == sizeof(debug_classes)/sizeof(debug_classes[0])) /* bad class name, skip it */
155                 continue;
156         }
157         else
158         {
159             if (*p == '-') clear = ~0;
160             else set = ~0;
161         }
162         if (*p == '+' || *p == '-') p++;
163         if (!p[0]) continue;
164
165         if (!strcmp( p, "all" ))
166             default_flags = (default_flags & ~clear) | set;
167         else
168             add_option( p, set, clear );
169     }
170     free( options );
171 }
172
173
174 /* print the usage message */
175 static void debug_usage(void)
176 {
177     static const char usage[] =
178         "Syntax of the WINEDEBUG variable:\n"
179         "  WINEDEBUG=[class]+xxx,[class]-yyy,...\n\n"
180         "Example: WINEDEBUG=+all,warn-heap\n"
181         "    turns on all messages except warning heap messages\n"
182         "Available message classes: err, warn, fixme, trace\n";
183     write( 2, usage, sizeof(usage) - 1 );
184     exit(1);
185 }
186
187
188 /* initialize all options at startup */
189 static void debug_init(void)
190 {
191     char *wine_debug;
192     struct stat st1, st2;
193
194     if (nb_debug_options != -1) return;  /* already initialized */
195     nb_debug_options = 0;
196
197     /* check for stderr pointing to /dev/null */
198     if (!fstat( 2, &st1 ) && S_ISCHR(st1.st_mode) &&
199         !stat( "/dev/null", &st2 ) && S_ISCHR(st2.st_mode) &&
200         st1.st_rdev == st2.st_rdev)
201     {
202         default_flags = 0;
203         return;
204     }
205     if ((wine_debug = getenv("WINEDEBUG")))
206     {
207         if (!strcmp( wine_debug, "help" )) debug_usage();
208         parse_options( wine_debug );
209     }
210 }
211
212 /* varargs wrapper for funcs.dbg_vprintf */
213 int wine_dbg_printf( const char *format, ... )
214 {
215     int ret;
216     va_list valist;
217
218     va_start(valist, format);
219     ret = funcs.dbg_vprintf( format, valist );
220     va_end(valist);
221     return ret;
222 }
223
224 /* printf with temp buffer allocation */
225 const char *wine_dbg_sprintf( const char *format, ... )
226 {
227     static const int max_size = 200;
228     char *ret;
229     int len;
230     va_list valist;
231
232     va_start(valist, format);
233     ret = funcs.get_temp_buffer( max_size );
234     len = vsnprintf( ret, max_size, format, valist );
235     if (len == -1 || len >= max_size) ret[max_size-1] = 0;
236     else funcs.release_temp_buffer( ret, len + 1 );
237     va_end(valist);
238     return ret;
239 }
240
241
242 /* varargs wrapper for funcs.dbg_vlog */
243 int wine_dbg_log( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
244                   const char *func, const char *format, ... )
245 {
246     int ret;
247     va_list valist;
248
249     if (!(__wine_dbg_get_channel_flags( channel ) & (1 << cls))) return -1;
250
251     va_start(valist, format);
252     ret = funcs.dbg_vlog( cls, channel, func, format, valist );
253     va_end(valist);
254     return ret;
255 }
256
257
258 /* allocate some tmp string space */
259 /* FIXME: this is not 100% thread-safe */
260 static char *get_temp_buffer( size_t size )
261 {
262     static char *list[32];
263     static int pos;
264     char *ret;
265     int idx;
266
267     idx = interlocked_xchg_add( &pos, 1 ) % (sizeof(list)/sizeof(list[0]));
268     if ((ret = realloc( list[idx], size ))) list[idx] = ret;
269     return ret;
270 }
271
272
273 /* release unused part of the buffer */
274 static void release_temp_buffer( char *buffer, size_t size )
275 {
276     /* don't bother doing anything */
277 }
278
279
280 /* default implementation of wine_dbgstr_an */
281 static const char *default_dbgstr_an( const char *str, int n )
282 {
283     static const char hex[16] = "0123456789abcdef";
284     char *dst, *res;
285     size_t size;
286
287     if (!((ULONG_PTR)str >> 16))
288     {
289         if (!str) return "(null)";
290         res = funcs.get_temp_buffer( 6 );
291         sprintf( res, "#%04x", LOWORD(str) );
292         return res;
293     }
294     if (n == -1) n = strlen(str);
295     if (n < 0) n = 0;
296     size = 10 + min( 300, n * 4 );
297     dst = res = funcs.get_temp_buffer( size );
298     *dst++ = '"';
299     while (n-- > 0 && dst <= res + size - 9)
300     {
301         unsigned char c = *str++;
302         switch (c)
303         {
304         case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
305         case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
306         case '\t': *dst++ = '\\'; *dst++ = 't'; break;
307         case '"':  *dst++ = '\\'; *dst++ = '"'; break;
308         case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
309         default:
310             if (c >= ' ' && c <= 126)
311                 *dst++ = c;
312             else
313             {
314                 *dst++ = '\\';
315                 *dst++ = 'x';
316                 *dst++ = hex[(c >> 4) & 0x0f];
317                 *dst++ = hex[c & 0x0f];
318             }
319         }
320     }
321     *dst++ = '"';
322     if (n > 0)
323     {
324         *dst++ = '.';
325         *dst++ = '.';
326         *dst++ = '.';
327     }
328     *dst++ = 0;
329     funcs.release_temp_buffer( res, dst - res );
330     return res;
331 }
332
333
334 /* default implementation of wine_dbgstr_wn */
335 static const char *default_dbgstr_wn( const WCHAR *str, int n )
336 {
337     char *dst, *res;
338     size_t size;
339
340     if (!((ULONG_PTR)str >> 16))
341     {
342         if (!str) return "(null)";
343         res = funcs.get_temp_buffer( 6 );
344         sprintf( res, "#%04x", LOWORD(str) );
345         return res;
346     }
347     if (n == -1)
348     {
349         const WCHAR *end = str;
350         while (*end) end++;
351         n = end - str;
352     }
353     if (n < 0) n = 0;
354     size = 12 + min( 300, n * 5 );
355     dst = res = funcs.get_temp_buffer( size );
356     *dst++ = 'L';
357     *dst++ = '"';
358     while (n-- > 0 && dst <= res + size - 10)
359     {
360         WCHAR c = *str++;
361         switch (c)
362         {
363         case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
364         case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
365         case '\t': *dst++ = '\\'; *dst++ = 't'; break;
366         case '"':  *dst++ = '\\'; *dst++ = '"'; break;
367         case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
368         default:
369             if (c >= ' ' && c <= 126)
370                 *dst++ = c;
371             else
372             {
373                 *dst++ = '\\';
374                 sprintf(dst,"%04x",c);
375                 dst+=4;
376             }
377         }
378     }
379     *dst++ = '"';
380     if (n > 0)
381     {
382         *dst++ = '.';
383         *dst++ = '.';
384         *dst++ = '.';
385     }
386     *dst++ = 0;
387     funcs.release_temp_buffer( res, dst - res );
388     return res;
389 }
390
391
392 /* default implementation of wine_dbg_vprintf */
393 static int default_dbg_vprintf( const char *format, va_list args )
394 {
395     return vfprintf( stderr, format, args );
396 }
397
398
399 /* default implementation of wine_dbg_vlog */
400 static int default_dbg_vlog( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
401                              const char *func, const char *format, va_list args )
402 {
403     int ret = 0;
404
405     if (cls < sizeof(debug_classes)/sizeof(debug_classes[0]))
406         ret += wine_dbg_printf( "%s:%s:%s ", debug_classes[cls], channel->name, func );
407     if (format)
408         ret += funcs.dbg_vprintf( format, args );
409     return ret;
410 }
411
412 /* wrappers to use the function pointers */
413
414 const char *wine_dbgstr_an( const char * s, int n )
415 {
416     return funcs.dbgstr_an(s, n);
417 }
418
419 const char *wine_dbgstr_wn( const WCHAR *s, int n )
420 {
421     return funcs.dbgstr_wn(s, n);
422 }
423
424 void __wine_dbg_set_functions( const struct __wine_debug_functions *new_funcs,
425                                struct __wine_debug_functions *old_funcs, size_t size )
426 {
427     if (old_funcs) memcpy( old_funcs, &funcs, min(sizeof(funcs),size) );
428     if (new_funcs) memcpy( &funcs, new_funcs, min(sizeof(funcs),size) );
429 }
430
431 static struct __wine_debug_functions funcs =
432 {
433     get_temp_buffer,
434     release_temp_buffer,
435     default_dbgstr_an,
436     default_dbgstr_wn,
437     default_dbg_vprintf,
438     default_dbg_vlog
439 };