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