Fixed crash.
[wine] / misc / debugstr.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <ctype.h>
6
7 #include "debugtools.h"
8 #include "thread.h"
9 #include "winbase.h"
10 #include "winnt.h"
11 #include "wtypes.h"
12
13 /* ---------------------------------------------------------------------- */
14
15 struct debug_info
16 {
17     char *str_pos;       /* current position in strings buffer */
18     char *out_pos;       /* current position in output buffer */
19     char  strings[500];  /* buffer for temporary strings */
20     char  output[500];   /* current output line */
21 };
22
23 static struct debug_info tmp;
24
25 static inline struct debug_info *get_info(void)
26 {
27     struct debug_info *info = NtCurrentTeb()->debug_info;
28     if (!info)
29     {
30         /* setup the temp structure in case HeapAlloc wants to print something */
31         NtCurrentTeb()->debug_info = &tmp;
32         tmp.str_pos = tmp.strings;
33         tmp.out_pos = tmp.output;
34         info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
35         info->str_pos = info->strings;
36         info->out_pos = info->output;
37         NtCurrentTeb()->debug_info = info;
38     }
39     return info;
40 }
41
42 /* ---------------------------------------------------------------------- */
43
44 static void *
45 gimme1 (int n)
46 {
47     struct debug_info *info = get_info();
48     char *res = info->str_pos;
49
50     if (res + n >= &info->strings[sizeof(info->strings)]) res = info->strings;
51     info->str_pos = res + n;
52     return res;
53 }
54
55 /* ---------------------------------------------------------------------- */
56
57 /* release extra space that we requested in gimme1() */
58 static inline void release( void *ptr )
59 {
60     struct debug_info *info = NtCurrentTeb()->debug_info;
61     info->str_pos = ptr;
62 }
63
64 /* ---------------------------------------------------------------------- */
65
66 LPCSTR debugstr_an (LPCSTR src, int n)
67 {
68   LPSTR dst, res;
69
70   if (!src) return "(null)";
71   if (n < 0) n = 0;
72   dst = res = gimme1 (n * 4 + 6);
73   *dst++ = '"';
74   while (n-- > 0 && *src)
75     {
76       BYTE c = *src++;
77       switch (c)
78         {
79         case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
80         case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
81         case '\t': *dst++ = '\\'; *dst++ = 't'; break;
82         case '"': *dst++ = '\\'; *dst++ = '"'; break;
83         case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
84         default:
85           if (c >= ' ' && c <= 126)
86             *dst++ = c;
87           else
88             {
89               *dst++ = '\\';
90               *dst++ = '0' + ((c >> 6) & 7);
91               *dst++ = '0' + ((c >> 3) & 7);
92               *dst++ = '0' + ((c >> 0) & 7);
93             }
94         }
95     }
96   *dst++ = '"';
97   if (*src)
98     {
99       *dst++ = '.';
100       *dst++ = '.';
101       *dst++ = '.';
102     }
103   *dst++ = '\0';
104   release( dst );
105   return res;
106 }
107
108 /* ---------------------------------------------------------------------- */
109
110 LPCSTR debugstr_wn (LPCWSTR src, int n)
111 {
112   LPSTR dst, res;
113
114   if (!src) return "(null)";
115   if (n < 0) n = 0;
116   dst = res = gimme1 (n * 5 + 7);
117   *dst++ = 'L';
118   *dst++ = '"';
119   while (n-- > 0 && *src)
120     {
121       WORD c = *src++;
122       switch (c)
123         {
124         case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
125         case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
126         case '\t': *dst++ = '\\'; *dst++ = 't'; break;
127         case '"': *dst++ = '\\'; *dst++ = '"'; break;
128         case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
129         default:
130           if (c >= ' ' && c <= 126)
131             *dst++ = c;
132           else 
133             {
134               *dst++ = '\\';
135               sprintf(dst,"%04x",c);
136               dst+=4;
137             }
138         }
139     }
140   *dst++ = '"';
141   if (*src)
142     {
143       *dst++ = '.';
144       *dst++ = '.';
145       *dst++ = '.';
146     }
147   *dst++ = '\0';
148   release( dst );
149   return res;
150 }
151
152 /* ---------------------------------------------------------------------- */
153 /* This routine returns a nicely formated name of the resource res
154    If the resource name is a string, it will return '<res-name>'
155    If it is a number, it will return #<4-digit-hex-number> */
156 LPCSTR debugres_a( LPCSTR res )
157 {
158     char *resname;
159     if (HIWORD(res)) return debugstr_a(res);
160     resname = gimme1(6);
161     sprintf(resname, "#%04x", LOWORD(res) );
162     return resname;
163 }
164
165 LPCSTR debugres_w( LPCWSTR res )
166 {
167     char *resname;
168     if (HIWORD(res)) return debugstr_w(res);
169     resname = gimme1(6);
170     sprintf( resname, "#%04x", LOWORD(res) );
171     return resname;
172 }
173
174 /* ---------------------------------------------------------------------- */
175
176 LPCSTR debugstr_guid( const GUID *id )
177 {
178     LPSTR str;
179
180     if (!id) return "(null)";
181     if (!HIWORD(id))
182     {
183         str = gimme1(12);
184         sprintf( str, "<guid-0x%04x>", LOWORD(id) );
185     }
186     else
187     {
188         str = gimme1(40);
189         sprintf( str, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
190                  id->Data1, id->Data2, id->Data3,
191                  id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
192                  id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
193     }
194     return str;
195 }
196
197 /* ---------------------------------------------------------------------- */
198
199 int dbg_vprintf( const char *format, va_list args )
200 {
201     struct debug_info *info = get_info();
202
203     int ret = vsprintf( info->out_pos, format, args );
204     char *p = strrchr( info->out_pos, '\n' );
205     if (!p) info->out_pos += ret;
206     else
207     {
208         char *pos = info->output;
209         p++;
210         write( 2, pos, p - pos );
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
220 int dbg_printf(const char *format, ...)
221 {
222     int ret;
223     va_list valist;
224
225     va_start(valist, format);
226     ret = dbg_vprintf( format, valist);
227     va_end(valist);
228     return ret;
229 }
230
231
232 /*--< Function >---------------------------------------------------------
233 **  
234 **              debugstr_hex_dump
235 **              
236 **  Description:
237 **      This function creates a hex dump, with a readable ascii
238 **  section, for displaying memory.
239 **  
240 **  Parameters:
241 **      1.  ptr             Pointer to memory
242 **      2.  len             How much to dump.
243 **
244 **  Returns:
245 **    Temporarily allocated buffer, with the hex dump in it.
246 **  Don't rely on this pointer being around for very long, just
247 **  long enough to use it in a TRACE statement; e.g.:
248 **  TRACE("struct dump is \n%s", debugstr_hex_dump(&x, sizeof(x)));
249 **          
250 **-------------------------------------------------------------------------*/
251 LPCSTR debugstr_hex_dump (const void *ptr, int len)
252 {
253     /* Locals */
254     char          dumpbuf[59];
255     char          charbuf[20];
256     char          tempbuf[8];
257     const char    *p;
258     int           i;
259     unsigned int  nosign;
260     LPSTR         dst;
261     LPSTR         outptr;
262
263 /* Begin function dbg_hex_dump */
264
265     /*-----------------------------------------------------------------------
266     **  Allocate an output buffer
267     **      A reasonable value is one line overhand (80 chars), and
268     **      then one line (80) for every 16 bytes.
269     **---------------------------------------------------------------------*/
270     outptr = dst = gimme1 ((len * (80 / 16)) + 80);
271
272     /*-----------------------------------------------------------------------
273     **  Loop throught the input buffer, one character at a time
274     **---------------------------------------------------------------------*/
275     for (i = 0, p = ptr; (i < len); i++, p++)
276     {
277
278         /*-------------------------------------------------------------------
279         **  If we're just starting a line, 
280         **      we need to possibly flush the old line, and then
281         **      intialize the line buffer.
282         **-----------------------------------------------------------------*/
283         if ((i % 16) == 0)
284         {
285             if (i)
286             {
287                 sprintf(outptr, "  %-43.43s   %-16.16s\n", dumpbuf, charbuf);
288                 outptr += strlen(outptr);
289             }
290             sprintf (dumpbuf, "%04x: ", i);
291             strcpy (charbuf, "");
292         }
293
294         /*-------------------------------------------------------------------
295         **  Add the current data byte to the dump section.
296         **-----------------------------------------------------------------*/
297         nosign = (unsigned char) *p;
298         sprintf (tempbuf, "%02X", nosign);
299
300         /*-------------------------------------------------------------------
301         **  If we're two DWORDS through, add a hyphen for readability,
302         **      if it's a DWORD boundary, add a space for more
303         **      readability.
304         **-----------------------------------------------------------------*/
305         if ((i % 16) == 7)
306             strcat(tempbuf, " - ");
307         else if ( (i % 4) == 3)
308             strcat(tempbuf, " ");
309         strcat (dumpbuf, tempbuf);
310
311         /*-------------------------------------------------------------------
312         **  Add the current byte to the character display part of the
313         **      hex dump
314         **-----------------------------------------------------------------*/
315         sprintf (tempbuf, "%c", isprint(*p) ? *p : '.');
316         strcat (charbuf, tempbuf);
317     }
318
319     /*-----------------------------------------------------------------------
320     **  Flush the last line, if any
321     **---------------------------------------------------------------------*/
322     if (i > 0)
323     {
324         sprintf(outptr, "  %-43.43s   %-16.16s\n", dumpbuf, charbuf);
325         outptr += strlen(outptr);
326     }
327
328     return(dst);
329 } /* End function dbg_hex_dump */
330
331
332