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