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) */
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
)
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';
79 if (*p
== '.') /* precision field */
82 while ((*p
>= '0') && (*p
<= '9'))
84 res
->precision
= res
->precision
* 10 + *p
- '0';
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
++; }
94 res
->type
= (res
->flags
& WPRINTF_LONG
) ? WPR_WCHAR
: WPR_CHAR
;
97 res
->type
= (res
->flags
& WPRINTF_SHORT
) ? WPR_CHAR
: WPR_WCHAR
;
101 res
->type
= WPR_SIGNED
;
104 res
->type
= (res
->flags
& (WPRINTF_LONG
|WPRINTF_WIDE
))
105 ? WPR_WSTRING
: WPR_STRING
;
108 res
->type
= (res
->flags
& (WPRINTF_SHORT
|WPRINTF_WIDE
))
109 ? WPR_STRING
: WPR_WSTRING
;
112 res
->type
= WPR_UNSIGNED
;
115 res
->flags
|= WPRINTF_UPPER_HEX
;
118 res
->type
= WPR_HEXA
;
120 default: /* unknown format char */
121 res
->type
= WPR_UNKNOWN
;
122 p
--; /* print format as normal char */
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
)
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';
153 if (*p
== '.') /* precision field */
156 while ((*p
>= '0') && (*p
<= '9'))
158 res
->precision
= res
->precision
* 10 + *p
- '0';
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
++; }
168 res
->type
= (res
->flags
& WPRINTF_SHORT
) ? WPR_CHAR
: WPR_WCHAR
;
171 res
->type
= (res
->flags
& WPRINTF_LONG
) ? WPR_WCHAR
: WPR_CHAR
;
175 res
->type
= WPR_SIGNED
;
178 res
->type
= ((res
->flags
& WPRINTF_SHORT
) && !(res
->flags
& WPRINTF_WIDE
)) ? WPR_STRING
: WPR_WSTRING
;
181 res
->type
= (res
->flags
& (WPRINTF_LONG
|WPRINTF_WIDE
)) ? WPR_WSTRING
: WPR_STRING
;
184 res
->type
= WPR_UNSIGNED
;
187 res
->flags
|= WPRINTF_UPPER_HEX
;
190 res
->type
= WPR_HEXA
;
193 res
->type
= WPR_UNKNOWN
;
194 p
--; /* print format as normal char */
197 return (INT
)(p
- format
) + 1;
201 /***********************************************************************
204 static UINT
WPRINTF_GetLen( WPRINTF_FORMAT
*format
, WPRINTF_DATA
*arg
,
205 LPSTR number
, UINT maxlen
)
209 if (format
->flags
& WPRINTF_LEFTALIGN
) format
->flags
&= ~WPRINTF_ZEROPAD
;
210 if (format
->width
> maxlen
) format
->width
= maxlen
;
215 return (format
->precision
= 1);
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
);
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
);
229 len
= sprintf( number
, "%d", arg
->int_view
);
232 len
= sprintf( number
, "%u", (UINT
)arg
->int_view
);
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;
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
;
251 /***********************************************************************
252 * WPRINTF_ExtractVAPtr (Not a Windows API)
254 static WPRINTF_DATA
WPRINTF_ExtractVAPtr( WPRINTF_FORMAT
*format
, va_list* args
)
260 result
.wchar_view
= va_arg( *args
, WCHAR
); break;
262 result
.char_view
= va_arg( *args
, CHAR
); break;
264 result
.lpcstr_view
= va_arg( *args
, LPCSTR
); break;
266 result
.lpcwstr_view
= va_arg( *args
, LPCWSTR
); break;
270 result
.int_view
= va_arg( *args
, INT
); break;
272 result
.wchar_view
= 0; break;
277 /***********************************************************************
278 * wvsnprintf16 (Not a Windows API)
280 INT16 WINAPI
wvsnprintf16( LPSTR buffer
, UINT16 maxlen
, LPCSTR spec
,
283 WPRINTF_FORMAT format
;
287 WPRINTF_DATA cur_arg
;
290 while (*spec
&& (maxlen
> 1))
292 if (*spec
!= '%') { *p
++ = *spec
++; maxlen
--; continue; }
294 if (*spec
== '%') { *p
++ = *spec
++; maxlen
--; continue; }
295 spec
+= WPRINTF_ParseFormatA( spec
, &format
);
298 case WPR_WCHAR
: /* No Unicode in Win16 */
300 cur_arg
.char_view
= VA_ARG16( args
, CHAR
);
302 case WPR_WSTRING
: /* No Unicode in Win16 */
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
);
309 if (!(format
.flags
& WPRINTF_LONG
))
311 cur_arg
.int_view
= VA_ARG16( args
, INT16
);
317 if (format
.flags
& WPRINTF_LONG
)
318 cur_arg
.int_view
= VA_ARG16( args
, UINT
);
320 cur_arg
.int_view
= VA_ARG16( args
, UINT16
);
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
--)
331 case WPR_WCHAR
: /* No Unicode in Win16 */
333 *p
= cur_arg
.char_view
;
335 else if (format
.width
> 1) *p
++ = ' ';
338 case WPR_WSTRING
: /* No Unicode in Win16 */
340 if (len
) memcpy( p
, cur_arg
.lpcstr_view
, len
);
344 if ((format
.flags
& WPRINTF_PREFIX_HEX
) && (maxlen
> 3))
347 *p
++ = (format
.flags
& WPRINTF_UPPER_HEX
) ? 'X' : 'x';
350 format
.precision
-= 2;
356 for (i
= len
; i
< format
.precision
; i
++, maxlen
--) *p
++ = '0';
357 if (len
) memcpy( p
, number
, len
);
363 if (format
.flags
& WPRINTF_LEFTALIGN
)
364 for (i
= format
.precision
; i
< format
.width
; i
++, maxlen
--)
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
,
379 WPRINTF_FORMAT format
;
383 WPRINTF_DATA argData
= (WPRINTF_DATA
)0;
385 while (*spec
&& (maxlen
> 1))
387 if (*spec
!= '%') { *p
++ = *spec
++; maxlen
--; continue; }
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
--)
399 *p
= argData
.wchar_view
;
401 else if (format
.width
> 1) *p
++ = ' ';
405 *p
= argData
.char_view
;
407 else if (format
.width
> 1) *p
++ = ' ';
411 memcpy( p
, argData
.lpcstr_view
, len
);
416 LPCWSTR ptr
= argData
.lpcwstr_view
;
417 for (i
= 0; i
< len
; i
++) *p
++ = (CHAR
)*ptr
++;
421 if ((format
.flags
& WPRINTF_PREFIX_HEX
) && (maxlen
> 3))
424 *p
++ = (format
.flags
& WPRINTF_UPPER_HEX
) ? 'X' : 'x';
427 format
.precision
-= 2;
433 for (i
= len
; i
< format
.precision
; i
++, maxlen
--) *p
++ = '0';
434 memcpy( p
, number
, len
);
436 /* Go to the next arg */
441 if (format
.flags
& WPRINTF_LEFTALIGN
)
442 for (i
= format
.precision
; i
< format
.width
; i
++, maxlen
--)
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
,
458 WPRINTF_FORMAT format
;
463 while (*spec
&& (maxlen
> 1))
465 if (*spec
!= '%') { *p
++ = *spec
++; maxlen
--; continue; }
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
--)
476 *p
= va_arg( args
, WCHAR
);
478 else if (format
.width
> 1) *p
++ = ' ';
482 *p
= (WCHAR
)va_arg( args
, CHAR
);
484 else if (format
.width
> 1) *p
++ = ' ';
489 LPCSTR ptr
= va_arg( args
, LPCSTR
);
490 for (i
= 0; i
< len
; i
++) *p
++ = (WCHAR
)*ptr
++;
494 if (len
) memcpy( p
, va_arg( args
, LPCWSTR
), len
* sizeof(WCHAR
) );
498 if ((format
.flags
& WPRINTF_PREFIX_HEX
) && (maxlen
> 3))
501 *p
++ = (format
.flags
& WPRINTF_UPPER_HEX
) ? 'X' : 'x';
504 format
.precision
-= 2;
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 */
517 if (format
.flags
& WPRINTF_LEFTALIGN
)
518 for (i
= format
.precision
; i
< format
.width
; i
++, maxlen
--)
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
, ... )
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
);
574 /* Emulator version */
575 INT16 WINAPIV
WIN16_wsprintf16(void)
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
);
592 /***********************************************************************
593 * wsprintfA (USER32.585)
595 INT WINAPIV
wsprintfA( LPSTR buffer
, LPCSTR spec
, ... )
600 TRACE(string
,"for %p got:\n",buffer
);
601 va_start( valist
, spec
);
602 res
= wvsnprintfA( buffer
, 0xffffffff, spec
, valist
);
608 /***********************************************************************
609 * wsprintfW (USER32.586)
611 INT WINAPIV
wsprintfW( LPWSTR buffer
, LPCWSTR spec
, ... )
616 TRACE(string
,"wsprintfW for %p\n",buffer
);
617 va_start( valist
, spec
);
618 res
= wvsnprintfW( buffer
, 0xffffffff, spec
, valist
);
624 /***********************************************************************
625 * wsnprintf16 (Not a Windows API)
627 INT16 WINAPIV
wsnprintf16( LPSTR buffer
, UINT16 maxlen
, LPCSTR spec
, ... )
632 va_start( valist
, spec
);
633 res
= wvsnprintf16( buffer
, maxlen
, spec
, valist
);
639 /***********************************************************************
640 * wsnprintfA (Not a Windows API)
642 INT WINAPIV
wsnprintfA( LPSTR buffer
, UINT maxlen
, LPCSTR spec
, ... )
647 va_start( valist
, spec
);
648 res
= wvsnprintfA( buffer
, maxlen
, spec
, valist
);
654 /***********************************************************************
655 * wsnprintfW (Not a Windows API)
657 INT WINAPIV
wsnprintfW( LPWSTR buffer
, UINT maxlen
, LPCWSTR spec
, ... )
662 va_start( valist
, spec
);
663 res
= wvsnprintfW( buffer
, maxlen
, spec
, valist
);