2 * ntdll printf functions
4 * Copyright 1999, 2009 Alexandre Julliard
5 * Copyright 2000 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define APICHAR wchar_t
24 #define APISTR(str) L"" str
25 #define FUNC_NAME(func) func ## _w
28 #define APISTR(str) str
29 #define FUNC_NAME(func) func ## _a
37 } FUNC_NAME(pf_output
);
40 * writes a string of characters to the output
41 * returns -1 if the string doesn't fit in the output buffer
42 * return the length of the string if all characters were written
44 static int FUNC_NAME(pf_output_wstr
)( FUNC_NAME(pf_output
) *out
, const WCHAR
*str
, int len
)
46 SIZE_T space
= out
->len
- out
->used
;
47 APICHAR
*p
= out
->buf
+ out
->used
;
50 if (len
< 0) len
= wcslen( str
);
54 if (out
->buf
) memcpy( p
, str
, min( n
, space
) * sizeof(WCHAR
) );
56 RtlUnicodeToMultiByteSize( &n
, str
, len
* sizeof(WCHAR
) );
57 if (out
->buf
) RtlUnicodeToMultiByteN( p
, min( n
, space
), NULL
, str
, len
* sizeof(WCHAR
) );
59 if (out
->buf
&& space
< n
) /* overflow */
68 static int FUNC_NAME(pf_output_str
)( FUNC_NAME(pf_output
) *out
, const char *str
, int len
)
70 SIZE_T space
= out
->len
- out
->used
;
71 APICHAR
*p
= out
->buf
+ out
->used
;
74 if (len
< 0) len
= strlen( str
);
77 RtlMultiByteToUnicodeSize( &n
, str
, len
);
79 if (out
->buf
) RtlMultiByteToUnicodeN( p
, min( n
, space
) * sizeof(WCHAR
), NULL
, str
, len
);
82 if (out
->buf
) memcpy( p
, str
, min( n
, space
));
84 if (out
->buf
&& space
< n
) /* overflow */
93 static int FUNC_NAME(pf_output_string
)( FUNC_NAME(pf_output
) *out
, const APICHAR
*str
, int len
)
96 return FUNC_NAME(pf_output_wstr
)( out
, str
, len
);
98 return FUNC_NAME(pf_output_str
)( out
, str
, len
);
102 /* pf_fill: takes care of signs, alignment, zero and field padding */
103 static int FUNC_NAME(pf_fill_left
)( FUNC_NAME(pf_output
) *out
, int len
, pf_flags
*flags
)
107 if (flags
->Sign
&& !(flags
->Format
== 'd' || flags
->Format
== 'i')) flags
->Sign
= 0;
111 APICHAR ch
= flags
->Sign
;
112 flags
->FieldLength
--;
113 if (flags
->PadZero
) r
= FUNC_NAME(pf_output_string
)( out
, &ch
, 1 );
115 if (!flags
->LeftAlign
)
117 APICHAR ch
= flags
->PadZero
? '0' : ' ';
118 for (i
= 0; i
< flags
->FieldLength
- len
&& r
>= 0; i
++)
119 r
= FUNC_NAME(pf_output_string
)( out
, &ch
, 1 );
121 if (flags
->Sign
&& !flags
->PadZero
&& r
>= 0)
123 APICHAR ch
= flags
->Sign
;
124 r
= FUNC_NAME(pf_output_string
)( out
, &ch
, 1 );
129 static int FUNC_NAME(pf_fill_right
)( FUNC_NAME(pf_output
) *out
, int len
, pf_flags
*flags
)
134 if (!flags
->LeftAlign
) return 0;
136 for (i
= 0; i
< flags
->FieldLength
- len
&& r
>= 0; i
++)
137 r
= FUNC_NAME(pf_output_string
)( out
, &ch
, 1 );
141 static int FUNC_NAME(pf_output_format_wstr
)( FUNC_NAME(pf_output
) *out
, const wchar_t *str
, int len
,
148 /* Do not search past the length specified by the precision. */
149 if (flags
->Precision
>= 0)
151 for (len
= 0; len
< flags
->Precision
; len
++) if (!str
[len
]) break;
153 else len
= wcslen( str
);
156 if (flags
->Precision
>= 0 && flags
->Precision
< len
) len
= flags
->Precision
;
158 r
= FUNC_NAME(pf_fill_left
)( out
, len
, flags
);
159 if (r
>= 0) r
= FUNC_NAME(pf_output_wstr
)( out
, str
, len
);
160 if (r
>= 0) r
= FUNC_NAME(pf_fill_right
)( out
, len
, flags
);
164 static int FUNC_NAME(pf_output_format_str
)( FUNC_NAME(pf_output
) *out
, const char *str
, int len
,
171 /* Do not search past the length specified by the precision. */
172 if (flags
->Precision
>= 0)
174 for (len
= 0; len
< flags
->Precision
; len
++) if (!str
[len
]) break;
176 else len
= strlen(str
);
179 if (flags
->Precision
>= 0 && flags
->Precision
< len
) len
= flags
->Precision
;
181 r
= FUNC_NAME(pf_fill_left
)( out
, len
, flags
);
182 if (r
>= 0) r
= FUNC_NAME(pf_output_str
)( out
, str
, len
);
183 if (r
>= 0) r
= FUNC_NAME(pf_fill_right
)( out
, len
, flags
);
187 static int FUNC_NAME(pf_output_format
)( FUNC_NAME(pf_output
) *out
, const APICHAR
*str
, int len
,
191 return FUNC_NAME(pf_output_format_wstr
)( out
, str
, len
, flags
);
193 return FUNC_NAME(pf_output_format_str
)( out
, str
, len
, flags
);
197 static int FUNC_NAME(pf_handle_string_format
)( FUNC_NAME(pf_output
) *out
, const void* str
, int len
,
198 pf_flags
*flags
, BOOL inverted
)
200 if (str
== NULL
) /* catch NULL pointer */
201 return FUNC_NAME(pf_output_format
)( out
, APISTR("(null)"), -1, flags
);
203 /* prefixes take priority over %c,%s vs. %C,%S, so we handle them first */
204 if (flags
->WideString
|| flags
->IntegerLength
== LEN_LONG
)
205 return FUNC_NAME(pf_output_format_wstr
)( out
, str
, len
, flags
);
206 if (flags
->IntegerLength
== LEN_SHORT
)
207 return FUNC_NAME(pf_output_format_str
)( out
, str
, len
, flags
);
209 /* %s,%c -> chars in ansi functions & wchars in unicode
210 * %S,%C -> wchars in ansi functions & chars in unicode */
211 if (!inverted
) return FUNC_NAME(pf_output_format
)( out
, str
, len
, flags
);
213 return FUNC_NAME(pf_output_format_str
)( out
, str
, len
, flags
);
215 return FUNC_NAME(pf_output_format_wstr
)( out
, str
, len
, flags
);
219 /* pf_integer_conv: prints x to buf, including alternate formats and
220 additional precision digits, but not field characters or the sign */
221 static void FUNC_NAME(pf_integer_conv
)( APICHAR
*buf
, pf_flags
*flags
, LONGLONG x
)
224 const APICHAR
*digits
;
227 if( flags
->Format
== 'o' )
229 else if( flags
->Format
== 'x' || flags
->Format
== 'X' )
234 if( flags
->Format
== 'X' )
235 digits
= APISTR("0123456789ABCDEFX");
237 digits
= APISTR("0123456789abcdefx");
239 if( x
< 0 && ( flags
->Format
== 'd' || flags
->Format
== 'i' ) )
248 flags
->Alternate
= FALSE
;
249 if( flags
->Precision
)
255 j
= (ULONGLONG
) x
% base
;
256 x
= (ULONGLONG
) x
/ base
;
257 buf
[i
++] = digits
[j
];
259 k
= flags
->Precision
- i
;
262 if( flags
->Alternate
)
266 buf
[i
++] = digits
[16];
269 else if( base
== 8 && buf
[i
-1] != '0' )
273 /* Adjust precision so pf_fill won't truncate the number later */
274 flags
->Precision
= i
;
279 APICHAR tmp
= buf
[j
];
286 static int FUNC_NAME(pf_vsnprintf
)( FUNC_NAME(pf_output
) *out
, const APICHAR
*format
, __ms_va_list valist
)
289 const APICHAR
*q
, *p
= format
;
294 for (q
= p
; *q
; q
++) if (*q
== '%') break;
298 r
= FUNC_NAME(pf_output_string
)(out
, p
, q
- p
);
305 /* output a single % character */
308 r
= FUNC_NAME(pf_output_string
)(out
, p
++, 1);
314 /* parse the flags */
315 memset( &flags
, 0, sizeof flags
);
318 if( *p
== '+' || *p
== ' ' )
320 if ( flags
.Sign
!= '+' )
324 flags
.LeftAlign
= TRUE
;
326 flags
.PadZero
= TRUE
;
328 flags
.Alternate
= TRUE
;
334 /* deal with the field width specifier */
335 flags
.FieldLength
= 0;
338 flags
.FieldLength
= va_arg( valist
, int );
339 if (flags
.FieldLength
< 0)
341 flags
.LeftAlign
= TRUE
;
342 flags
.FieldLength
= -flags
.FieldLength
;
346 else while (*p
>= '0' && *p
<= '9')
348 flags
.FieldLength
*= 10;
349 flags
.FieldLength
+= *p
++ - '0';
352 /* deal with precision */
353 flags
.Precision
= -1;
360 flags
.Precision
= va_arg( valist
, int );
363 else while (*p
>= '0' && *p
<= '9')
365 flags
.Precision
*= 10;
366 flags
.Precision
+= *p
++ - '0';
370 /* deal with integer width modifier */
373 if (*p
== 'l' && *(p
+1) == 'l')
375 flags
.IntegerDouble
= TRUE
;
380 flags
.IntegerLength
= LEN_LONG
;
389 flags
.IntegerLength
= LEN_SHORT
;
394 if( *(p
+1) == '6' && *(p
+2) == '4' )
396 flags
.IntegerDouble
= TRUE
;
399 else if( *(p
+1) == '3' && *(p
+2) == '2' )
401 else if( p
[1] && strchr( "diouxX", p
[1] ) )
403 if( sizeof(void *) == 8 )
404 flags
.IntegerDouble
= TRUE
;
407 else if ((p
[1] >= '0' && p
[1] <= '9') || !p
[1])
414 flags
.WideString
= TRUE
;
417 else if ((*p
== 'z' || *p
== 't') && p
[1] && strchr("diouxX", p
[1]))
419 flags
.IntegerNative
= TRUE
;
424 flags
.IntegerDouble
= TRUE
;
436 if (flags
.Format
== '$')
438 FIXME("Positional parameters are not supported (%s)\n", FUNC_NAME(wine_dbgstr
)(format
));
441 /* output a string */
442 if( flags
.Format
== 's' || flags
.Format
== 'S' )
443 r
= FUNC_NAME(pf_handle_string_format
)( out
, va_arg(valist
, const void*), -1,
444 &flags
, (flags
.Format
== 'S') );
446 /* output a single character */
447 else if( flags
.Format
== 'c' || flags
.Format
== 'C' )
449 APICHAR ch
= (APICHAR
)va_arg( valist
, int );
450 r
= FUNC_NAME(pf_handle_string_format
)( out
, &ch
, 1, &flags
, (flags
.Format
== 'C') );
453 /* output a pointer */
454 else if( flags
.Format
== 'p' )
457 void *ptr
= va_arg( valist
, void * );
458 int prec
= flags
.Precision
;
460 flags
.PadZero
= TRUE
;
461 flags
.Precision
= 2*sizeof(void*);
462 FUNC_NAME(pf_integer_conv
)( pointer
, &flags
, (ULONG_PTR
)ptr
);
463 flags
.PadZero
= FALSE
;
464 flags
.Precision
= prec
;
465 r
= FUNC_NAME(pf_output_format
)( out
, pointer
, -1, &flags
);
469 else if( flags
.Format
== 'n' )
471 int *x
= va_arg(valist
, int *);
474 else if( flags
.Format
&& strchr("diouxX", flags
.Format
))
476 APICHAR number
[40], *x
= number
;
479 /* 0 padding is added after '0x' if Alternate flag is in use */
480 if((flags
.Format
=='x' || flags
.Format
=='X') && flags
.PadZero
&& flags
.Alternate
481 && !flags
.LeftAlign
&& flags
.Precision
<flags
.FieldLength
-2)
482 flags
.Precision
= flags
.FieldLength
- 2;
484 max_len
= (flags
.FieldLength
>flags
.Precision
? flags
.FieldLength
: flags
.Precision
) + 10;
485 if(max_len
> ARRAY_SIZE(number
))
486 if (!(x
= RtlAllocateHeap( GetProcessHeap(), 0, max_len
* sizeof(*x
) ))) return -1;
488 if(flags
.IntegerDouble
|| (flags
.IntegerNative
&& sizeof(void*) == 8))
489 FUNC_NAME(pf_integer_conv
)( x
, &flags
, va_arg(valist
, LONGLONG
) );
490 else if(flags
.Format
=='d' || flags
.Format
=='i')
491 FUNC_NAME(pf_integer_conv
)( x
, &flags
, flags
.IntegerLength
!= LEN_SHORT
?
492 va_arg(valist
, int) : (short)va_arg(valist
, int) );
494 FUNC_NAME(pf_integer_conv
)( x
, &flags
, flags
.IntegerLength
!= LEN_SHORT
?
495 (unsigned int)va_arg(valist
, int) : (unsigned short)va_arg(valist
, int) );
497 r
= FUNC_NAME(pf_output_format
)( out
, x
, -1, &flags
);
499 RtlFreeHeap( GetProcessHeap(), 0, x
);