Fixed DdeGetData when called for getting size.
[wine] / dlls / user / wsprintf.c
1 /*
2  * wsprintf functions
3  *
4  * Copyright 1996 Alexandre Julliard
5  */
6
7 #include <stdarg.h>
8 #include <string.h>
9 #include <stdio.h>
10
11 #include "winbase.h"
12 #include "wingdi.h"
13 #include "winuser.h"
14
15 #include "wine/winbase16.h"
16 #include "wine/winuser16.h"
17 #include "stackframe.h"
18
19 #include "debugtools.h"
20
21 DEFAULT_DEBUG_CHANNEL(string);
22
23
24 #define WPRINTF_LEFTALIGN   0x0001  /* Align output on the left ('-' prefix) */
25 #define WPRINTF_PREFIX_HEX  0x0002  /* Prefix hex with 0x ('#' prefix) */
26 #define WPRINTF_ZEROPAD     0x0004  /* Pad with zeros ('0' prefix) */
27 #define WPRINTF_LONG        0x0008  /* Long arg ('l' prefix) */
28 #define WPRINTF_SHORT       0x0010  /* Short arg ('h' prefix) */
29 #define WPRINTF_UPPER_HEX   0x0020  /* Upper-case hex ('X' specifier) */
30 #define WPRINTF_WIDE        0x0040  /* Wide arg ('w' prefix) */
31
32 typedef enum
33 {
34     WPR_UNKNOWN,
35     WPR_CHAR,
36     WPR_WCHAR,
37     WPR_STRING,
38     WPR_WSTRING,
39     WPR_SIGNED,
40     WPR_UNSIGNED,
41     WPR_HEXA
42 } WPRINTF_TYPE;
43
44 typedef struct
45 {
46     UINT         flags;
47     UINT         width;
48     UINT         precision;
49     WPRINTF_TYPE   type;
50 } WPRINTF_FORMAT;
51
52 typedef union {
53     WCHAR   wchar_view;
54     CHAR    char_view;
55     LPCSTR  lpcstr_view;
56     LPCWSTR lpcwstr_view;
57     INT     int_view;
58 } WPRINTF_DATA;
59
60 static const CHAR null_stringA[] = "(null)";
61 static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 };
62
63 /***********************************************************************
64  *           WPRINTF_ParseFormatA
65  *
66  * Parse a format specification. A format specification has the form:
67  *
68  * [-][#][0][width][.precision]type
69  *
70  * Return value is the length of the format specification in characters.
71  */
72 static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res )
73 {
74     LPCSTR p = format;
75
76     res->flags = 0;
77     res->width = 0;
78     res->precision = 0;
79     if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
80     if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
81     if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
82     while ((*p >= '0') && (*p <= '9'))  /* width field */
83     {
84         res->width = res->width * 10 + *p - '0';
85         p++;
86     }
87     if (*p == '.')  /* precision field */
88     {
89         p++;
90         while ((*p >= '0') && (*p <= '9'))
91         {
92             res->precision = res->precision * 10 + *p - '0';
93             p++;
94         }
95     }
96     if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
97     else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
98     else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
99     switch(*p)
100     {
101     case 'c':
102         res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
103         break;
104     case 'C':
105         res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
106         break;
107     case 'd':
108     case 'i':
109         res->type = WPR_SIGNED;
110         break;
111     case 's':
112         res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
113         break;
114     case 'S':
115         res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
116         break;
117     case 'u':
118         res->type = WPR_UNSIGNED;
119         break;
120     case 'X':
121         res->flags |= WPRINTF_UPPER_HEX;
122         /* fall through */
123     case 'x':
124         res->type = WPR_HEXA;
125         break;
126     default: /* unknown format char */
127         res->type = WPR_UNKNOWN;
128         p--;  /* print format as normal char */
129         break;
130     }
131     return (INT)(p - format) + 1;
132 }
133
134
135 /***********************************************************************
136  *           WPRINTF_ParseFormatW
137  *
138  * Parse a format specification. A format specification has the form:
139  *
140  * [-][#][0][width][.precision]type
141  *
142  * Return value is the length of the format specification in characters.
143  */
144 static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res )
145 {
146     LPCWSTR p = format;
147
148     res->flags = 0;
149     res->width = 0;
150     res->precision = 0;
151     if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
152     if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
153     if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
154     while ((*p >= '0') && (*p <= '9'))  /* width field */
155     {
156         res->width = res->width * 10 + *p - '0';
157         p++;
158     }
159     if (*p == '.')  /* precision field */
160     {
161         p++;
162         while ((*p >= '0') && (*p <= '9'))
163         {
164             res->precision = res->precision * 10 + *p - '0';
165             p++;
166         }
167     }
168     if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
169     else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
170     else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
171     switch((CHAR)*p)
172     {
173     case 'c':
174         res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
175         break;
176     case 'C':
177         res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
178         break;
179     case 'd':
180     case 'i':
181         res->type = WPR_SIGNED;
182         break;
183     case 's':
184         res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
185         break;
186     case 'S':
187         res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
188         break;
189     case 'u':
190         res->type = WPR_UNSIGNED;
191         break;
192     case 'X':
193         res->flags |= WPRINTF_UPPER_HEX;
194         /* fall through */
195     case 'x':
196         res->type = WPR_HEXA;
197         break;
198     default:
199         res->type = WPR_UNKNOWN;
200         p--;  /* print format as normal char */
201         break;
202     }
203     return (INT)(p - format) + 1;
204 }
205
206
207 /***********************************************************************
208  *           WPRINTF_GetLen
209  */
210 static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg,
211                               LPSTR number, UINT maxlen )
212 {
213     UINT len;
214
215     if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD;
216     if (format->width > maxlen) format->width = maxlen;
217     switch(format->type)
218     {
219     case WPR_CHAR:
220     case WPR_WCHAR:
221         return (format->precision = 1);
222     case WPR_STRING:
223         if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA;
224         for (len = 0; !format->precision || (len < format->precision); len++)
225             if (!*(arg->lpcstr_view + len)) break;
226         if (len > maxlen) len = maxlen;
227         return (format->precision = len);
228     case WPR_WSTRING:
229         if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW;
230         for (len = 0; !format->precision || (len < format->precision); len++)
231             if (!*(arg->lpcwstr_view + len)) break;
232         if (len > maxlen) len = maxlen;
233         return (format->precision = len);
234     case WPR_SIGNED:
235         len = sprintf( number, "%d", arg->int_view );
236         break;
237     case WPR_UNSIGNED:
238         len = sprintf( number, "%u", (UINT)arg->int_view );
239         break;
240     case WPR_HEXA:
241         len = sprintf( number,
242                        (format->flags & WPRINTF_UPPER_HEX) ? "%X" : "%x",
243                        (UINT)arg->int_view);
244         break;
245     default:
246         return 0;
247     }
248     if (len > maxlen) len = maxlen;
249     if (format->precision < len) format->precision = len;
250     if (format->precision > maxlen) format->precision = maxlen;
251     if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision))
252         format->precision = format->width;
253     if (format->flags & WPRINTF_PREFIX_HEX) len += 2;
254     return len;
255 }
256
257
258 /***********************************************************************
259  *           wvsnprintf16   (Not a Windows API)
260  */
261 static INT16 wvsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec,
262                            LPCVOID args )
263 {
264     WPRINTF_FORMAT format;
265     LPSTR p = buffer;
266     UINT i, len;
267     CHAR number[20];
268     WPRINTF_DATA cur_arg;
269     SEGPTR seg_str;
270
271     while (*spec && (maxlen > 1))
272     {
273         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
274         spec++;
275         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
276         spec += WPRINTF_ParseFormatA( spec, &format );
277         switch(format.type)
278         {
279         case WPR_WCHAR:  /* No Unicode in Win16 */
280         case WPR_CHAR:
281             cur_arg.char_view = VA_ARG16( args, CHAR );
282             break;
283         case WPR_WSTRING:  /* No Unicode in Win16 */
284         case WPR_STRING:
285             seg_str = VA_ARG16( args, SEGPTR );
286             if (IsBadReadPtr16(seg_str, 1 )) cur_arg.lpcstr_view = "";
287             else cur_arg.lpcstr_view = MapSL( seg_str );
288             break;
289         case WPR_SIGNED:
290             if (!(format.flags & WPRINTF_LONG))
291             {
292                 cur_arg.int_view = VA_ARG16( args, INT16 );
293                 break;
294             }
295             /* fall through */
296         case WPR_HEXA:
297         case WPR_UNSIGNED:
298             if (format.flags & WPRINTF_LONG)
299                 cur_arg.int_view = VA_ARG16( args, UINT );
300             else
301                 cur_arg.int_view = VA_ARG16( args, UINT16 );
302             break;
303         case WPR_UNKNOWN:
304             continue;
305         }
306         len = WPRINTF_GetLen( &format, &cur_arg, number, maxlen - 1 );
307         if (!(format.flags & WPRINTF_LEFTALIGN))
308             for (i = format.precision; i < format.width; i++, maxlen--)
309                 *p++ = ' ';
310         switch(format.type)
311         {
312         case WPR_WCHAR:  /* No Unicode in Win16 */
313         case WPR_CHAR:
314             *p= cur_arg.char_view;
315             /* wsprintf16 (unlike wsprintf) ignores null characters */
316             if (*p != '\0') p++;
317             else if (format.width > 1) *p++ = ' ';
318             else len = 0;
319             break;
320         case WPR_WSTRING:  /* No Unicode in Win16 */
321         case WPR_STRING:
322             if (len) memcpy( p, cur_arg.lpcstr_view, len );
323             p += len;
324             break;
325         case WPR_HEXA:
326             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
327             {
328                 *p++ = '0';
329                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
330                 maxlen -= 2;
331                 len -= 2;
332             }
333             /* fall through */
334         case WPR_SIGNED:
335         case WPR_UNSIGNED:
336             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
337             if (len) memcpy( p, number, len );
338             p += len;
339             break;
340         case WPR_UNKNOWN:
341             continue;
342         }
343         if (format.flags & WPRINTF_LEFTALIGN)
344             for (i = format.precision; i < format.width; i++, maxlen--)
345                 *p++ = ' ';
346         maxlen -= len;
347     }
348     *p = 0;
349     return (maxlen > 1) ? (INT)(p - buffer) : -1;
350 }
351
352
353 /***********************************************************************
354  *           wvsnprintfA   (USER32.@) (Not a Windows API, but we export it from USER32 anyway)
355  */
356 INT WINAPI wvsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec, va_list args )
357 {
358     WPRINTF_FORMAT format;
359     LPSTR p = buffer;
360     UINT i, len;
361     CHAR number[20];
362     WPRINTF_DATA argData;
363
364     TRACE("%p %u %s\n", buffer, maxlen, debugstr_a(spec));
365
366     while (*spec && (maxlen > 1))
367     {
368         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
369         spec++;
370         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
371         spec += WPRINTF_ParseFormatA( spec, &format );
372
373         switch(format.type)
374         {
375         case WPR_WCHAR:
376             argData.wchar_view = (WCHAR)va_arg( args, int );
377             break;
378         case WPR_CHAR:
379             argData.char_view = (CHAR)va_arg( args, int );
380             break;
381         case WPR_STRING:
382             argData.lpcstr_view = va_arg( args, LPCSTR );
383             break;
384         case WPR_WSTRING:
385             argData.lpcwstr_view = va_arg( args, LPCWSTR );
386             break;
387         case WPR_HEXA:
388         case WPR_SIGNED:
389         case WPR_UNSIGNED:
390             argData.int_view = va_arg( args, INT );
391             break;
392         default:
393             argData.wchar_view = 0;
394             break;
395         }
396
397         len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
398         if (!(format.flags & WPRINTF_LEFTALIGN))
399             for (i = format.precision; i < format.width; i++, maxlen--)
400                 *p++ = ' ';
401         switch(format.type)
402         {
403         case WPR_WCHAR:
404             *p++ = argData.wchar_view;
405             break;
406         case WPR_CHAR:
407             *p++ = argData.char_view;
408             break;
409         case WPR_STRING:
410             memcpy( p, argData.lpcstr_view, len );
411             p += len;
412             break;
413         case WPR_WSTRING:
414             {
415                 LPCWSTR ptr = argData.lpcwstr_view;
416                 for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++;
417             }
418             break;
419         case WPR_HEXA:
420             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
421             {
422                 *p++ = '0';
423                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
424                 maxlen -= 2;
425                 len -= 2;
426             }
427             /* fall through */
428         case WPR_SIGNED:
429         case WPR_UNSIGNED:
430             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
431             memcpy( p, number, len );
432             p += len;
433             break;
434         case WPR_UNKNOWN:
435             continue;
436         }
437         if (format.flags & WPRINTF_LEFTALIGN)
438             for (i = format.precision; i < format.width; i++, maxlen--)
439                 *p++ = ' ';
440         maxlen -= len;
441     }
442     *p = 0;
443     TRACE("%s\n",debugstr_a(buffer));
444     return (maxlen > 1) ? (INT)(p - buffer) : -1;
445 }
446
447
448 /***********************************************************************
449  *           wvsnprintfW   (USER32.@) (Not a Windows API, but we export it from USER32 anyway)
450  */
451 INT WINAPI wvsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, va_list args )
452 {
453     WPRINTF_FORMAT format;
454     LPWSTR p = buffer;
455     UINT i, len;
456     CHAR number[20];
457     WPRINTF_DATA argData;
458
459     TRACE("%p %u %s\n", buffer, maxlen, debugstr_w(spec));
460
461     while (*spec && (maxlen > 1))
462     {
463         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
464         spec++;
465         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
466         spec += WPRINTF_ParseFormatW( spec, &format );
467
468         switch(format.type)
469         {
470         case WPR_WCHAR:
471             argData.wchar_view = (WCHAR)va_arg( args, int );
472             break;
473         case WPR_CHAR:
474             argData.char_view = (CHAR)va_arg( args, int );
475             break;
476         case WPR_STRING:
477             argData.lpcstr_view = va_arg( args, LPCSTR );
478             break;
479         case WPR_WSTRING:
480             argData.lpcwstr_view = va_arg( args, LPCWSTR );
481             break;
482         case WPR_HEXA:
483         case WPR_SIGNED:
484         case WPR_UNSIGNED:
485             argData.int_view = va_arg( args, INT );
486             break;
487         default:
488             argData.wchar_view = 0;
489             break;
490         }
491
492         len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
493         if (!(format.flags & WPRINTF_LEFTALIGN))
494             for (i = format.precision; i < format.width; i++, maxlen--)
495                 *p++ = ' ';
496         switch(format.type)
497         {
498         case WPR_WCHAR:
499             *p++ = argData.wchar_view;
500             break;
501         case WPR_CHAR:
502             *p++ = argData.char_view;
503             break;
504         case WPR_STRING:
505             {
506                 LPCSTR ptr = argData.lpcstr_view;
507                 for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++;
508             }
509             break;
510         case WPR_WSTRING:
511             if (len) memcpy( p, argData.lpcwstr_view, len * sizeof(WCHAR) );
512             p += len;
513             break;
514         case WPR_HEXA:
515             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
516             {
517                 *p++ = '0';
518                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
519                 maxlen -= 2;
520                 len -= 2;
521             }
522             /* fall through */
523         case WPR_SIGNED:
524         case WPR_UNSIGNED:
525             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
526             for (i = 0; i < len; i++) *p++ = (WCHAR)number[i];
527             break;
528         case WPR_UNKNOWN:
529             continue;
530         }
531         if (format.flags & WPRINTF_LEFTALIGN)
532             for (i = format.precision; i < format.width; i++, maxlen--)
533                 *p++ = ' ';
534         maxlen -= len;
535     }
536     *p = 0;
537     TRACE("%s\n",debugstr_w(buffer));
538     return (maxlen > 1) ? (INT)(p - buffer) : -1;
539 }
540
541
542 /***********************************************************************
543  *           wvsprintf   (USER.421)
544  */
545 INT16 WINAPI wvsprintf16( LPSTR buffer, LPCSTR spec, LPCVOID args )
546 {
547     INT16 res;
548
549     TRACE("for %p got:\n",buffer);
550     res = wvsnprintf16( buffer, 1024, spec, args );
551     return ( res == -1 ) ? 1024 : res;
552 }
553
554
555 /***********************************************************************
556  *           wvsprintfA   (USER32.@)
557  */
558 INT WINAPI wvsprintfA( LPSTR buffer, LPCSTR spec, va_list args )
559 {
560     INT res = wvsnprintfA( buffer, 1024, spec, args );
561     return ( res == -1 ) ? 1024 : res;
562 }
563
564
565 /***********************************************************************
566  *           wvsprintfW   (USER32.@)
567  */
568 INT WINAPI wvsprintfW( LPWSTR buffer, LPCWSTR spec, va_list args )
569 {
570     INT res = wvsnprintfW( buffer, 1024, spec, args );
571     return ( res == -1 ) ? 1024 : res;
572 }
573
574
575 /***********************************************************************
576  *           _wsprintf   (USER.420)
577  */
578 INT16 WINAPIV wsprintf16(void)
579 {
580     VA_LIST16 valist;
581     INT16 res;
582     SEGPTR buffer, spec;
583
584     VA_START16( valist );
585     buffer = VA_ARG16( valist, SEGPTR );
586     spec   = VA_ARG16( valist, SEGPTR );
587     res = wvsnprintf16( MapSL(buffer), 1024, MapSL(spec), valist );
588     VA_END16( valist );
589     return ( res == -1 ) ? 1024 : res;
590 }
591
592
593 /***********************************************************************
594  *           wsprintfA   (USER32.@)
595  */
596 INT WINAPIV wsprintfA( LPSTR buffer, LPCSTR spec, ... )
597 {
598     va_list valist;
599     INT res;
600
601     va_start( valist, spec );
602     res = wvsnprintfA( buffer, 1024, spec, valist );
603     va_end( valist );
604     return ( res == -1 ) ? 1024 : res;
605 }
606
607
608 /***********************************************************************
609  *           wsprintfW   (USER32.@)
610  */
611 INT WINAPIV wsprintfW( LPWSTR buffer, LPCWSTR spec, ... )
612 {
613     va_list valist;
614     INT res;
615
616     va_start( valist, spec );
617     res = wvsnprintfW( buffer, 1024, spec, valist );
618     va_end( valist );
619     return ( res == -1 ) ? 1024 : res;
620 }