Fixed "Display Combination" call.
[wine/hacks.git] / misc / wsprintf.c
blobe67a2e0443a385ca7d37bc9c9c11ec75e8888cf9
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 typedef union {
45 WCHAR wchar_view;
46 CHAR char_view;
47 LPCSTR lpcstr_view;
48 LPCWSTR lpcwstr_view;
49 INT int_view;
50 } WPRINTF_DATA;
52 static const CHAR null_stringA[] = "(null)";
53 static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 };
55 /***********************************************************************
56 * WPRINTF_ParseFormatA
58 * Parse a format specification. A format specification has the form:
60 * [-][#][0][width][.precision]type
62 * Return value is the length of the format specification in characters.
64 static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res )
66 LPCSTR p = format;
68 res->flags = 0;
69 res->width = 0;
70 res->precision = 0;
71 if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
72 if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
73 if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
74 while ((*p >= '0') && (*p <= '9')) /* width field */
76 res->width = res->width * 10 + *p - '0';
77 p++;
79 if (*p == '.') /* precision field */
81 p++;
82 while ((*p >= '0') && (*p <= '9'))
84 res->precision = res->precision * 10 + *p - '0';
85 p++;
88 if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
89 else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
90 else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
91 switch(*p)
93 case 'c':
94 res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
95 break;
96 case 'C':
97 res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
98 break;
99 case 'd':
100 case 'i':
101 res->type = WPR_SIGNED;
102 break;
103 case 's':
104 res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE))
105 ? WPR_WSTRING : WPR_STRING;
106 break;
107 case 'S':
108 res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE))
109 ? WPR_STRING : WPR_WSTRING;
110 break;
111 case 'u':
112 res->type = WPR_UNSIGNED;
113 break;
114 case 'X':
115 res->flags |= WPRINTF_UPPER_HEX;
116 /* fall through */
117 case 'x':
118 res->type = WPR_HEXA;
119 break;
120 default: /* unknown format char */
121 res->type = WPR_UNKNOWN;
122 p--; /* print format as normal char */
123 break;
125 return (INT)(p - format) + 1;
129 /***********************************************************************
130 * WPRINTF_ParseFormatW
132 * Parse a format specification. A format specification has the form:
134 * [-][#][0][width][.precision]type
136 * Return value is the length of the format specification in characters.
138 static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res )
140 LPCWSTR p = format;
142 res->flags = 0;
143 res->width = 0;
144 res->precision = 0;
145 if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
146 if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
147 if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
148 while ((*p >= '0') && (*p <= '9')) /* width field */
150 res->width = res->width * 10 + *p - '0';
151 p++;
153 if (*p == '.') /* precision field */
155 p++;
156 while ((*p >= '0') && (*p <= '9'))
158 res->precision = res->precision * 10 + *p - '0';
159 p++;
162 if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
163 else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
164 else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
165 switch((CHAR)*p)
167 case 'c':
168 res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
169 break;
170 case 'C':
171 res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
172 break;
173 case 'd':
174 case 'i':
175 res->type = WPR_SIGNED;
176 break;
177 case 's':
178 res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
179 break;
180 case 'S':
181 res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
182 break;
183 case 'u':
184 res->type = WPR_UNSIGNED;
185 break;
186 case 'X':
187 res->flags |= WPRINTF_UPPER_HEX;
188 /* fall through */
189 case 'x':
190 res->type = WPR_HEXA;
191 break;
192 default:
193 res->type = WPR_UNKNOWN;
194 p--; /* print format as normal char */
195 break;
197 return (INT)(p - format) + 1;
201 /***********************************************************************
202 * WPRINTF_GetLen
204 static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg,
205 LPSTR number, UINT maxlen )
207 UINT len;
209 if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD;
210 if (format->width > maxlen) format->width = maxlen;
211 switch(format->type)
213 case WPR_CHAR:
214 case WPR_WCHAR:
215 return (format->precision = 1);
216 case WPR_STRING:
217 if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA;
218 for (len = 0; !format->precision || (len < format->precision); len++)
219 if (!arg->lpcstr_view + len) break;
220 if (len > maxlen) len = maxlen;
221 return (format->precision = len);
222 case WPR_WSTRING:
223 if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW;
224 for (len = 0; !format->precision || (len < format->precision); len++)
225 if (!*(arg->lpcwstr_view + len)) break;
226 if (len > maxlen) len = maxlen;
227 return (format->precision = len);
228 case WPR_SIGNED:
229 len = sprintf( number, "%d", arg->int_view );
230 break;
231 case WPR_UNSIGNED:
232 len = sprintf( number, "%u", (UINT)arg->int_view );
233 break;
234 case WPR_HEXA:
235 len = sprintf( number,
236 (format->flags & WPRINTF_UPPER_HEX) ? "%X" : "%x",
237 (UINT)arg->int_view);
238 if (format->flags & WPRINTF_PREFIX_HEX) len += 2;
239 break;
240 default:
241 return 0;
243 if (len > maxlen) len = maxlen;
244 if (format->precision < len) format->precision = len;
245 if (format->precision > maxlen) format->precision = maxlen;
246 if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision))
247 format->precision = format->width;
248 return len;
251 /***********************************************************************
252 * WPRINTF_ExtractVAPtr (Not a Windows API)
254 static WPRINTF_DATA WPRINTF_ExtractVAPtr( WPRINTF_FORMAT *format, va_list* args )
256 WPRINTF_DATA result;
257 switch(format->type)
259 case WPR_WCHAR:
260 result.wchar_view = va_arg( *args, WCHAR ); break;
261 case WPR_CHAR:
262 result.char_view = va_arg( *args, CHAR ); break;
263 case WPR_STRING:
264 result.lpcstr_view = va_arg( *args, LPCSTR); break;
265 case WPR_WSTRING:
266 result.lpcwstr_view = va_arg( *args, LPCWSTR); break;
267 case WPR_HEXA:
268 case WPR_SIGNED:
269 case WPR_UNSIGNED:
270 result.int_view = va_arg( *args, INT ); break;
271 default:
272 result.wchar_view = 0; break;
274 return result;
277 /***********************************************************************
278 * wvsnprintf16 (Not a Windows API)
280 INT16 WINAPI wvsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec,
281 LPCVOID args )
283 WPRINTF_FORMAT format;
284 LPSTR p = buffer;
285 UINT i, len;
286 CHAR number[20];
287 WPRINTF_DATA cur_arg;
288 SEGPTR seg_str;
290 while (*spec && (maxlen > 1))
292 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
293 spec++;
294 if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
295 spec += WPRINTF_ParseFormatA( spec, &format );
296 switch(format.type)
298 case WPR_WCHAR: /* No Unicode in Win16 */
299 case WPR_CHAR:
300 cur_arg.char_view = VA_ARG16( args, CHAR );
301 break;
302 case WPR_WSTRING: /* No Unicode in Win16 */
303 case WPR_STRING:
304 seg_str = VA_ARG16( args, SEGPTR );
305 if (IsBadReadPtr16(seg_str, 1 )) cur_arg.lpcstr_view = "";
306 else cur_arg.lpcstr_view = PTR_SEG_TO_LIN( seg_str );
307 break;
308 case WPR_SIGNED:
309 if (!(format.flags & WPRINTF_LONG))
311 cur_arg.int_view = VA_ARG16( args, INT16 );
312 break;
314 /* fall through */
315 case WPR_HEXA:
316 case WPR_UNSIGNED:
317 if (format.flags & WPRINTF_LONG)
318 cur_arg.int_view = VA_ARG16( args, UINT );
319 else
320 cur_arg.int_view = VA_ARG16( args, UINT16 );
321 break;
322 case WPR_UNKNOWN:
323 continue;
325 len = WPRINTF_GetLen( &format, &cur_arg, number, maxlen - 1 );
326 if (!(format.flags & WPRINTF_LEFTALIGN))
327 for (i = format.precision; i < format.width; i++, maxlen--)
328 *p++ = ' ';
329 switch(format.type)
331 case WPR_WCHAR: /* No Unicode in Win16 */
332 case WPR_CHAR:
333 *p= cur_arg.char_view;
334 if (*p != '\0') p++;
335 else if (format.width > 1) *p++ = ' ';
336 else len = 0;
337 break;
338 case WPR_WSTRING: /* No Unicode in Win16 */
339 case WPR_STRING:
340 if (len) memcpy( p, cur_arg.lpcstr_view, len );
341 p += len;
342 break;
343 case WPR_HEXA:
344 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
346 *p++ = '0';
347 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
348 maxlen -= 2;
349 len -= 2;
350 format.precision -= 2;
351 format.width -= 2;
353 /* fall through */
354 case WPR_SIGNED:
355 case WPR_UNSIGNED:
356 for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
357 if (len) memcpy( p, number, len );
358 p += len;
359 break;
360 case WPR_UNKNOWN:
361 continue;
363 if (format.flags & WPRINTF_LEFTALIGN)
364 for (i = format.precision; i < format.width; i++, maxlen--)
365 *p++ = ' ';
366 maxlen -= len;
368 *p = 0;
369 return (maxlen > 1) ? (INT)(p - buffer) : -1;
373 /***********************************************************************
374 * wvsnprintfA (Not a Windows API)
376 INT WINAPI wvsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec,
377 va_list args )
379 WPRINTF_FORMAT format;
380 LPSTR p = buffer;
381 UINT i, len;
382 CHAR number[20];
383 WPRINTF_DATA argData = (WPRINTF_DATA)0;
385 while (*spec && (maxlen > 1))
387 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
388 spec++;
389 if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
390 spec += WPRINTF_ParseFormatA( spec, &format );
391 argData = WPRINTF_ExtractVAPtr( &format, &args );
392 len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
393 if (!(format.flags & WPRINTF_LEFTALIGN))
394 for (i = format.precision; i < format.width; i++, maxlen--)
395 *p++ = ' ';
396 switch(format.type)
398 case WPR_WCHAR:
399 *p = argData.wchar_view;
400 if (*p != '\0') p++;
401 else if (format.width > 1) *p++ = ' ';
402 else len = 0;
403 break;
404 case WPR_CHAR:
405 *p = argData.char_view;
406 if (*p != '\0') p++;
407 else if (format.width > 1) *p++ = ' ';
408 else len = 0;
409 break;
410 case WPR_STRING:
411 memcpy( p, argData.lpcstr_view, len );
412 p += len;
413 break;
414 case WPR_WSTRING:
416 LPCWSTR ptr = argData.lpcwstr_view;
417 for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++;
419 break;
420 case WPR_HEXA:
421 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
423 *p++ = '0';
424 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
425 maxlen -= 2;
426 len -= 2;
427 format.precision -= 2;
428 format.width -= 2;
430 /* fall through */
431 case WPR_SIGNED:
432 case WPR_UNSIGNED:
433 for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
434 memcpy( p, number, len );
435 p += len;
436 /* Go to the next arg */
437 break;
438 case WPR_UNKNOWN:
439 continue;
441 if (format.flags & WPRINTF_LEFTALIGN)
442 for (i = format.precision; i < format.width; i++, maxlen--)
443 *p++ = ' ';
444 maxlen -= len;
446 *p = 0;
447 TRACE(string,"%s\n",buffer);
448 return (maxlen > 1) ? (INT)(p - buffer) : -1;
452 /***********************************************************************
453 * wvsnprintfW (Not a Windows API)
455 INT WINAPI wvsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec,
456 va_list args )
458 WPRINTF_FORMAT format;
459 LPWSTR p = buffer;
460 UINT i, len;
461 CHAR number[20];
463 while (*spec && (maxlen > 1))
465 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
466 spec++;
467 if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
468 spec += WPRINTF_ParseFormatW( spec, &format );
469 len = WPRINTF_GetLen( &format, args, number, maxlen - 1 );
470 if (!(format.flags & WPRINTF_LEFTALIGN))
471 for (i = format.precision; i < format.width; i++, maxlen--)
472 *p++ = ' ';
473 switch(format.type)
475 case WPR_WCHAR:
476 *p = va_arg( args, WCHAR );
477 if (*p != '\0') p++;
478 else if (format.width > 1) *p++ = ' ';
479 else len = 0;
480 break;
481 case WPR_CHAR:
482 *p = (WCHAR)va_arg( args, CHAR );
483 if (*p != '\0') p++;
484 else if (format.width > 1) *p++ = ' ';
485 else len = 0;
486 break;
487 case WPR_STRING:
489 LPCSTR ptr = va_arg( args, LPCSTR );
490 for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++;
492 break;
493 case WPR_WSTRING:
494 if (len) memcpy( p, va_arg( args, LPCWSTR ), len * sizeof(WCHAR) );
495 p += len;
496 break;
497 case WPR_HEXA:
498 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
500 *p++ = '0';
501 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
502 maxlen -= 2;
503 len -= 2;
504 format.precision -= 2;
505 format.width -= 2;
507 /* fall through */
508 case WPR_SIGNED:
509 case WPR_UNSIGNED:
510 for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
511 for (i = 0; i < len; i++) *p++ = (WCHAR)number[i];
512 (void)va_arg( args, INT ); /* Go to the next arg */
513 break;
514 case WPR_UNKNOWN:
515 continue;
517 if (format.flags & WPRINTF_LEFTALIGN)
518 for (i = format.precision; i < format.width; i++, maxlen--)
519 *p++ = ' ';
520 maxlen -= len;
522 *p = 0;
523 return (maxlen > 1) ? (INT)(p - buffer) : -1;
527 /***********************************************************************
528 * wvsprintf16 (USER.421)
530 INT16 WINAPI wvsprintf16( LPSTR buffer, LPCSTR spec, LPCVOID args )
532 TRACE(string,"for %p got:\n",buffer);
533 return wvsnprintf16( buffer, 0xffff, spec, args );
537 /***********************************************************************
538 * wvsprintfA (USER32.587)
540 INT WINAPI wvsprintfA( LPSTR buffer, LPCSTR spec, va_list args )
542 TRACE(string,"for %p got:\n",buffer);
543 return wvsnprintfA( buffer, 0xffffffff, spec, args );
547 /***********************************************************************
548 * wvsprintfW (USER32.588)
550 INT WINAPI wvsprintfW( LPWSTR buffer, LPCWSTR spec, va_list args )
552 TRACE(string,"for %p got:\n",buffer);
553 return wvsnprintfW( buffer, 0xffffffff, spec, args );
557 /***********************************************************************
558 * wsprintf16 (USER.420)
560 /* Winelib version */
561 INT16 WINAPIV wsprintf16( LPSTR buffer, LPCSTR spec, ... )
563 va_list valist;
564 INT16 res;
566 TRACE(string,"for %p got:\n",buffer);
567 va_start( valist, spec );
568 /* Note: we call the 32-bit version, because the args are 32-bit */
569 res = (INT16)wvsnprintfA( buffer, 0xffffffff, spec, valist );
570 va_end( valist );
571 return res;
574 /* Emulator version */
575 INT16 WINAPIV WIN16_wsprintf16(void)
577 VA_LIST16 valist;
578 INT16 res;
579 SEGPTR buffer, spec;
581 VA_START16( valist );
582 buffer = VA_ARG16( valist, SEGPTR );
583 spec = VA_ARG16( valist, SEGPTR );
584 TRACE(string,"got:\n");
585 res = wvsnprintf16( (LPSTR)PTR_SEG_TO_LIN(buffer), 0xffff,
586 (LPCSTR)PTR_SEG_TO_LIN(spec), valist );
587 VA_END16( valist );
588 return res;
592 /***********************************************************************
593 * wsprintfA (USER32.585)
595 INT WINAPIV wsprintfA( LPSTR buffer, LPCSTR spec, ... )
597 va_list valist;
598 INT res;
600 TRACE(string,"for %p got:\n",buffer);
601 va_start( valist, spec );
602 res = wvsnprintfA( buffer, 0xffffffff, spec, valist );
603 va_end( valist );
604 return res;
608 /***********************************************************************
609 * wsprintfW (USER32.586)
611 INT WINAPIV wsprintfW( LPWSTR buffer, LPCWSTR spec, ... )
613 va_list valist;
614 INT res;
616 TRACE(string,"wsprintfW for %p\n",buffer);
617 va_start( valist, spec );
618 res = wvsnprintfW( buffer, 0xffffffff, spec, valist );
619 va_end( valist );
620 return res;
624 /***********************************************************************
625 * wsnprintf16 (Not a Windows API)
627 INT16 WINAPIV wsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec, ... )
629 va_list valist;
630 INT16 res;
632 va_start( valist, spec );
633 res = wvsnprintf16( buffer, maxlen, spec, valist );
634 va_end( valist );
635 return res;
639 /***********************************************************************
640 * wsnprintfA (Not a Windows API)
642 INT WINAPIV wsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec, ... )
644 va_list valist;
645 INT res;
647 va_start( valist, spec );
648 res = wvsnprintfA( buffer, maxlen, spec, valist );
649 va_end( valist );
650 return res;
654 /***********************************************************************
655 * wsnprintfW (Not a Windows API)
657 INT WINAPIV wsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, ... )
659 va_list valist;
660 INT res;
662 va_start( valist, spec );
663 res = wvsnprintfW( buffer, maxlen, spec, valist );
664 va_end( valist );
665 return res;