Moved error codes to cderr.h.
[wine/multimedia.git] / misc / wsprintf.c
blobbba6946cf3afae05c5efb6e3e67ba3fcc0bd7844
1 /*
2 * wsprintf functions
4 * Copyright 1996 Alexandre Julliard
5 */
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"
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) */
24 typedef enum
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;
36 typedef struct
38 UINT flags;
39 UINT width;
40 UINT precision;
41 WPRINTF_TYPE type;
42 } WPRINTF_FORMAT;
44 static const CHAR null_stringA[] = "(null)";
45 static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 };
47 /***********************************************************************
48 * WPRINTF_ParseFormatA
50 * Parse a format specification. A format specification has the form:
52 * [-][#][0][width][.precision]type
54 * Return value is the length of the format specification in characters.
56 static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res )
58 LPCSTR p = format;
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 */
68 res->width = res->width * 10 + *p - '0';
69 p++;
71 if (*p == '.') /* precision field */
73 p++;
74 while ((*p >= '0') && (*p <= '9'))
76 res->precision = res->precision * 10 + *p - '0';
77 p++;
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)
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;
117 return (INT)(p - format) + 1;
121 /***********************************************************************
122 * WPRINTF_ParseFormatW
124 * Parse a format specification. A format specification has the form:
126 * [-][#][0][width][.precision]type
128 * Return value is the length of the format specification in characters.
130 static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res )
132 LPCWSTR p = format;
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 */
142 res->width = res->width * 10 + *p - '0';
143 p++;
145 if (*p == '.') /* precision field */
147 p++;
148 while ((*p >= '0') && (*p <= '9'))
150 res->precision = res->precision * 10 + *p - '0';
151 p++;
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)
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;
189 return (INT)(p - format) + 1;
193 /***********************************************************************
194 * WPRINTF_GetLen
196 static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, LPCVOID arg,
197 LPSTR number, UINT maxlen )
199 UINT len;
201 if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD;
202 if (format->width > maxlen) format->width = maxlen;
203 switch(format->type)
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;
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;
243 /***********************************************************************
244 * WPRINTF_ExtractVAPtr (Not a Windows API)
246 static LPVOID WPRINTF_ExtractVAPtr( WPRINTF_FORMAT *format, va_list* args )
248 switch(format->type)
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;
267 /***********************************************************************
268 * wvsnprintf16 (Not a Windows API)
270 INT16 WINAPI wvsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec,
271 LPCVOID args )
273 WPRINTF_FORMAT format;
274 LPSTR p = buffer;
275 UINT i, len;
276 CHAR number[20];
277 DWORD cur_arg;
279 while (*spec && (maxlen > 1))
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)
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))
300 cur_arg = (DWORD)(INT)VA_ARG16( args, INT16 );
301 break;
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;
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)
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))
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;
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;
351 if (format.flags & WPRINTF_LEFTALIGN)
352 for (i = format.precision; i < format.width; i++, maxlen--)
353 *p++ = ' ';
354 maxlen -= len;
356 *p = 0;
357 return (maxlen > 1) ? (INT)(p - buffer) : -1;
361 /***********************************************************************
362 * wvsnprintf32A (Not a Windows API)
364 INT WINAPI wvsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec,
365 va_list args )
367 WPRINTF_FORMAT format;
368 LPSTR p = buffer;
369 UINT i, len;
370 CHAR number[20];
371 LPVOID argPtr = NULL;
373 while (*spec && (maxlen > 1))
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)
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:
402 LPCWSTR ptr = (LPCWSTR)argPtr;
403 for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++;
405 break;
406 case WPR_HEXA:
407 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
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;
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;
427 if (format.flags & WPRINTF_LEFTALIGN)
428 for (i = format.precision; i < format.width; i++, maxlen--)
429 *p++ = ' ';
430 maxlen -= len;
432 *p = 0;
433 TRACE(string,"%s\n",buffer);
434 return (maxlen > 1) ? (INT)(p - buffer) : -1;
438 /***********************************************************************
439 * wvsnprintf32W (Not a Windows API)
441 INT WINAPI wvsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec,
442 va_list args )
444 WPRINTF_FORMAT format;
445 LPWSTR p = buffer;
446 UINT i, len;
447 CHAR number[20];
449 while (*spec && (maxlen > 1))
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)
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:
473 LPCSTR ptr = va_arg( args, LPCSTR );
474 for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++;
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))
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;
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;
501 if (format.flags & WPRINTF_LEFTALIGN)
502 for (i = format.precision; i < format.width; i++, maxlen--)
503 *p++ = ' ';
504 maxlen -= len;
506 *p = 0;
507 return (maxlen > 1) ? (INT)(p - buffer) : -1;
511 /***********************************************************************
512 * wvsprintf16 (USER.421)
514 INT16 WINAPI wvsprintf16( LPSTR buffer, LPCSTR spec, LPCVOID args )
516 TRACE(string,"for %p got:\n",buffer);
517 return wvsnprintf16( buffer, 0xffff, spec, args );
521 /***********************************************************************
522 * wvsprintf32A (USER32.587)
524 INT WINAPI wvsprintfA( LPSTR buffer, LPCSTR spec, va_list args )
526 TRACE(string,"for %p got:\n",buffer);
527 return wvsnprintfA( buffer, 0xffffffff, spec, args );
531 /***********************************************************************
532 * wvsprintf32W (USER32.588)
534 INT WINAPI wvsprintfW( LPWSTR buffer, LPCWSTR spec, va_list args )
536 TRACE(string,"for %p got:\n",buffer);
537 return wvsnprintfW( buffer, 0xffffffff, spec, args );
541 /***********************************************************************
542 * wsprintf16 (USER.420)
544 /* Winelib version */
545 INT16 WINAPIV wsprintf16( LPSTR buffer, LPCSTR spec, ... )
547 va_list valist;
548 INT16 res;
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;
558 /* Emulator version */
559 INT16 WINAPIV WIN16_wsprintf16(void)
561 VA_LIST16 valist;
562 INT16 res;
563 SEGPTR buffer, spec;
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;
576 /***********************************************************************
577 * wsprintf32A (USER32.585)
579 INT WINAPIV wsprintfA( LPSTR buffer, LPCSTR spec, ... )
581 va_list valist;
582 INT res;
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;
592 /***********************************************************************
593 * wsprintf32W (USER32.586)
595 INT WINAPIV wsprintfW( LPWSTR buffer, LPCWSTR spec, ... )
597 va_list valist;
598 INT res;
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;
608 /***********************************************************************
609 * wsnprintf16 (Not a Windows API)
611 INT16 WINAPIV wsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec, ... )
613 va_list valist;
614 INT16 res;
616 va_start( valist, spec );
617 res = wvsnprintf16( buffer, maxlen, spec, valist );
618 va_end( valist );
619 return res;
623 /***********************************************************************
624 * wsnprintf32A (Not a Windows API)
626 INT WINAPIV wsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec, ... )
628 va_list valist;
629 INT res;
631 va_start( valist, spec );
632 res = wvsnprintfA( buffer, maxlen, spec, valist );
633 va_end( valist );
634 return res;
638 /***********************************************************************
639 * wsnprintf32W (Not a Windows API)
641 INT WINAPIV wsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, ... )
643 va_list valist;
644 INT res;
646 va_start( valist, spec );
647 res = wvsnprintfW( buffer, maxlen, spec, valist );
648 va_end( valist );
649 return res;