4 * Copyright 1996 Alexandre Julliard
9 #include "wine/winbase16.h"
12 #include "stackframe.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) */
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 )
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';
71 if (*p == '.') /* precision field */
74 while ((*p >= '0') && (*p <= '9'))
76 res->precision = res->precision * 10 + *p - '0';
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++; }
86 res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
89 res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
93 res->type = WPR_SIGNED;
96 res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE))
97 ? WPR_WSTRING : WPR_STRING;
100 res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE))
101 ? WPR_STRING : WPR_WSTRING;
104 res->type = WPR_UNSIGNED;
107 res->flags |= WPRINTF_UPPER_HEX;
110 res->type = WPR_HEXA;
112 default: /* unknown format char */
113 res->type = WPR_UNKNOWN;
114 p--; /* print format as normal char */
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 )
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';
145 if (*p == '.') /* precision field */
148 while ((*p >= '0') && (*p <= '9'))
150 res->precision = res->precision * 10 + *p - '0';
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++; }
160 res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
163 res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
167 res->type = WPR_SIGNED;
170 res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
173 res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
176 res->type = WPR_UNSIGNED;
179 res->flags |= WPRINTF_UPPER_HEX;
182 res->type = WPR_HEXA;
185 res->type = WPR_UNKNOWN;
186 p--; /* print format as normal char */
189 return (INT)(p - format) + 1;
193 /***********************************************************************
196 static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, LPCVOID arg,
197 LPSTR number, UINT maxlen )
201 if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD;
202 if (format->width > maxlen) format->width = maxlen;
207 return (format->precision = 1);
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);
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);
221 len = sprintf( number, "%d", *(INT *)arg );
224 len = sprintf( number, "%u", *(UINT *)arg );
227 len = sprintf( number,
228 (format->flags & WPRINTF_UPPER_HEX) ? "%X" : "%x",
230 if (format->flags & WPRINTF_PREFIX_HEX) len += 2;
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;
243 /***********************************************************************
244 * WPRINTF_ExtractVAPtr (Not a Windows API)
246 static LPVOID WPRINTF_ExtractVAPtr( WPRINTF_FORMAT *format, va_list* args )
251 return (LPVOID)va_arg( *args, WCHAR );
253 return (LPVOID)va_arg( *args, CHAR );
255 return (LPVOID)va_arg( *args, LPCSTR);
257 return (LPVOID)va_arg( *args, LPCWSTR);
261 return (LPVOID)va_arg( *args, INT );
267 /***********************************************************************
268 * wvsnprintf16 (Not a Windows API)
270 INT16 WINAPI wvsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec,
273 WPRINTF_FORMAT format;
279 while (*spec && (maxlen > 1))
281 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
283 if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
284 spec += WPRINTF_ParseFormatA( spec, &format );
287 case WPR_WCHAR: /* No Unicode in Win16 */
289 cur_arg = (DWORD)VA_ARG16( args, CHAR );
291 case WPR_WSTRING: /* No Unicode in Win16 */
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 );
298 if (!(format.flags & WPRINTF_LONG))
300 cur_arg = (DWORD)(INT)VA_ARG16( args, INT16 );
306 if (format.flags & WPRINTF_LONG)
307 cur_arg = (DWORD)VA_ARG16( args, UINT );
309 cur_arg = (DWORD)VA_ARG16( args, UINT16 );
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--)
322 if ((*p = (CHAR)cur_arg)) p++;
323 else if (format.width > 1) *p++ = ' ';
328 if (len) memcpy( p, (LPCSTR)cur_arg, len );
332 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
335 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
338 format.precision -= 2;
344 for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
345 if (len) memcpy( p, number, len );
351 if (format.flags & WPRINTF_LEFTALIGN)
352 for (i = format.precision; i < format.width; i++, maxlen--)
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,
367 WPRINTF_FORMAT format;
371 LPVOID argPtr = NULL;
373 while (*spec && (maxlen > 1))
375 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
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--)
387 if ((*p = (CHAR)argPtr)) p++;
388 else if (format.width > 1) *p++ = ' ';
392 if ((*p = (CHAR)argPtr)) p++;
393 else if (format.width > 1) *p++ = ' ';
397 memcpy( p, (LPCSTR)argPtr, len );
402 LPCWSTR ptr = (LPCWSTR)argPtr;
403 for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++;
407 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
410 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
413 format.precision -= 2;
419 for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
420 memcpy( p, number, len );
422 /* Go to the next arg */
427 if (format.flags & WPRINTF_LEFTALIGN)
428 for (i = format.precision; i < format.width; i++, maxlen--)
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,
444 WPRINTF_FORMAT format;
449 while (*spec && (maxlen > 1))
451 if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
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--)
462 if ((*p = va_arg( args, WCHAR ))) p++;
463 else if (format.width > 1) *p++ = ' ';
467 if ((*p = (WCHAR)va_arg( args, CHAR ))) p++;
468 else if (format.width > 1) *p++ = ' ';
473 LPCSTR ptr = va_arg( args, LPCSTR );
474 for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++;
478 if (len) memcpy( p, va_arg( args, LPCWSTR ), len * sizeof(WCHAR) );
482 if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
485 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
488 format.precision -= 2;
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 */
501 if (format.flags & WPRINTF_LEFTALIGN)
502 for (i = format.precision; i < format.width; i++, maxlen--)
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, ... )
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 );
558 /* Emulator version */
559 INT16 WINAPIV WIN16_wsprintf16(void)
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 );
576 /***********************************************************************
577 * wsprintf32A (USER32.585)
579 INT WINAPIV wsprintfA( LPSTR buffer, LPCSTR spec, ... )
584 TRACE(string,"for %p got:\n",buffer);
585 va_start( valist, spec );
586 res = wvsnprintfA( buffer, 0xffffffff, spec, valist );
592 /***********************************************************************
593 * wsprintf32W (USER32.586)
595 INT WINAPIV wsprintfW( LPWSTR buffer, LPCWSTR spec, ... )
600 TRACE(string,"wsprintf32W for %p\n",buffer);
601 va_start( valist, spec );
602 res = wvsnprintfW( buffer, 0xffffffff, spec, valist );
608 /***********************************************************************
609 * wsnprintf16 (Not a Windows API)
611 INT16 WINAPIV wsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec, ... )
616 va_start( valist, spec );
617 res = wvsnprintf16( buffer, maxlen, spec, valist );
623 /***********************************************************************
624 * wsnprintf32A (Not a Windows API)
626 INT WINAPIV wsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec, ... )
631 va_start( valist, spec );
632 res = wvsnprintfA( buffer, maxlen, spec, valist );
638 /***********************************************************************
639 * wsnprintf32W (Not a Windows API)
641 INT WINAPIV wsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, ... )
646 va_start( valist, spec );
647 res = wvsnprintfW( buffer, maxlen, spec, valist );