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