Require {DECLARE,DEFAULT}_DEBUG_CHANNEL statements to end in a ;
[wine] / dlls / ntdll / debugtools.c
1 /*
2  * Debugging functions
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <ctype.h>
10
11 #include "debugtools.h"
12 #include "thread.h"
13 #include "winbase.h"
14 #include "winnt.h"
15 #include "wtypes.h"
16
17 /* ---------------------------------------------------------------------- */
18
19 struct debug_info
20 {
21     char *str_pos;       /* current position in strings buffer */
22     char *out_pos;       /* current position in output buffer */
23     char  strings[504];  /* buffer for temporary strings */
24     char  output[504];   /* current output line */
25 };
26
27 static struct debug_info tmp;
28
29 /* get the debug info pointer for the current thread */
30 static inline struct debug_info *get_info(void)
31 {
32     struct debug_info *info = NtCurrentTeb()->debug_info;
33     if (!info)
34     {
35         /* setup the temp structure in case HeapAlloc wants to print something */
36         NtCurrentTeb()->debug_info = &tmp;
37         tmp.str_pos = tmp.strings;
38         tmp.out_pos = tmp.output;
39         info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
40         info->str_pos = info->strings;
41         info->out_pos = info->output;
42         NtCurrentTeb()->debug_info = info;
43     }
44     return info;
45 }
46
47 /* allocate some tmp space for a string */
48 static void *gimme1(int n)
49 {
50     struct debug_info *info = get_info();
51     char *res = info->str_pos;
52
53     if (res + n >= &info->strings[sizeof(info->strings)]) res = info->strings;
54     info->str_pos = res + n;
55     return res;
56 }
57
58 /* release extra space that we requested in gimme1() */
59 static inline void release( void *ptr )
60 {
61     struct debug_info *info = NtCurrentTeb()->debug_info;
62     info->str_pos = ptr;
63 }
64
65 /***********************************************************************
66  *              wine_dbgstr_an
67  */
68 const char *wine_dbgstr_an( const char *src, int n )
69 {
70     char *dst, *res;
71
72     if (!HIWORD(src))
73     {
74         if (!src) return "(null)";
75         res = gimme1(6);
76         sprintf(res, "#%04x", LOWORD(src) );
77         return res;
78     }
79     if (n < 0) n = 0;
80     dst = res = gimme1 (n * 4 + 6);
81     *dst++ = '"';
82     while (n-- > 0 && *src)
83     {
84         unsigned char c = *src++;
85         switch (c)
86         {
87         case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
88         case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
89         case '\t': *dst++ = '\\'; *dst++ = 't'; break;
90         case '"': *dst++ = '\\'; *dst++ = '"'; break;
91         case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
92         default:
93             if (c >= ' ' && c <= 126)
94                 *dst++ = c;
95             else
96             {
97                 *dst++ = '\\';
98                 *dst++ = '0' + ((c >> 6) & 7);
99                 *dst++ = '0' + ((c >> 3) & 7);
100                 *dst++ = '0' + ((c >> 0) & 7);
101             }
102         }
103     }
104     *dst++ = '"';
105     if (*src)
106     {
107         *dst++ = '.';
108         *dst++ = '.';
109         *dst++ = '.';
110     }
111     *dst++ = '\0';
112     release( dst );
113     return res;
114 }
115
116 /***********************************************************************
117  *              wine_dbgstr_wn
118  */
119 const char *wine_dbgstr_wn( const WCHAR *src, int n )
120 {
121     char *dst, *res;
122
123     if (!HIWORD(src))
124     {
125         if (!src) return "(null)";
126         res = gimme1(6);
127         sprintf(res, "#%04x", LOWORD(src) );
128         return res;
129     }
130     if (n < 0) n = 0;
131     dst = res = gimme1 (n * 5 + 7);
132     *dst++ = 'L';
133     *dst++ = '"';
134     while (n-- > 0 && *src)
135     {
136         WCHAR c = *src++;
137         switch (c)
138         {
139         case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
140         case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
141         case '\t': *dst++ = '\\'; *dst++ = 't'; break;
142         case '"': *dst++ = '\\'; *dst++ = '"'; break;
143         case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
144         default:
145             if (c >= ' ' && c <= 126)
146                 *dst++ = c;
147             else
148             {
149                 *dst++ = '\\';
150                 sprintf(dst,"%04x",c);
151                 dst+=4;
152             }
153         }
154     }
155     *dst++ = '"';
156     if (*src)
157     {
158         *dst++ = '.';
159         *dst++ = '.';
160         *dst++ = '.';
161     }
162     *dst++ = '\0';
163     release( dst );
164     return res;
165 }
166
167 /***********************************************************************
168  *              wine_dbgstr_guid
169  */
170 const char *wine_dbgstr_guid( const GUID *id )
171 {
172     char *str;
173
174     if (!id) return "(null)";
175     if (!HIWORD(id))
176     {
177         str = gimme1(12);
178         sprintf( str, "<guid-0x%04x>", LOWORD(id) );
179     }
180     else
181     {
182         str = gimme1(40);
183         sprintf( str, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
184                  id->Data1, id->Data2, id->Data3,
185                  id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
186                  id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
187     }
188     return str;
189 }
190
191 /***********************************************************************
192  *              wine_dbg_vprintf
193  */
194 int wine_dbg_vprintf( const char *format, va_list args )
195 {
196     struct debug_info *info = get_info();
197
198     int ret = vsprintf( info->out_pos, format, args );
199     char *p = strrchr( info->out_pos, '\n' );
200     if (!p) info->out_pos += ret;
201     else
202     {
203         char *pos = info->output;
204         p++;
205         write( 2, pos, p - pos );
206         /* move beginning of next line to start of buffer */
207         while ((*pos = *p++)) pos++;
208         info->out_pos = pos;
209     }
210     return ret;
211 }
212
213 /***********************************************************************
214  *              wine_dbg_printf
215  */
216 int wine_dbg_printf(const char *format, ...)
217 {
218     int ret;
219     va_list valist;
220
221     va_start(valist, format);
222     ret = wine_dbg_vprintf( format, valist );
223     va_end(valist);
224     return ret;
225 }
226
227 /***********************************************************************
228  *              wine_dbg_log
229  */
230 int wine_dbg_log(enum __DEBUG_CLASS cls, const char *channel,
231                  const char *function, const char *format, ... )
232 {
233     static const char *classes[__DBCL_COUNT] = { "fixme", "err", "warn", "trace" };
234     va_list valist;
235     int ret = 0;
236
237     va_start(valist, format);
238     if (cls < __DBCL_COUNT)
239         ret = wine_dbg_printf( "%s:%s:%s ", classes[cls], channel + 1, function );
240     if (format)
241         ret += wine_dbg_vprintf( format, valist );
242     va_end(valist);
243     return ret;
244 }