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