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