winevulkan: Avoid zero-sized allocations.
[wine.git] / dlls / ntdll / printf.h
blob4fad5c0ddecc48e0f86d62b328585b3311b3c37b
1 /*
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
22 #ifdef PRINTF_WIDE
23 #define APICHAR wchar_t
24 #define APISTR(str) L"" str
25 #define FUNC_NAME(func) func ## _w
26 #else
27 #define APICHAR char
28 #define APISTR(str) str
29 #define FUNC_NAME(func) func ## _a
30 #endif
32 typedef struct
34 APICHAR *buf;
35 SIZE_T len;
36 SIZE_T used;
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;
48 ULONG n;
50 if (len < 0) len = wcslen( str );
52 #ifdef PRINTF_WIDE
53 n = len;
54 if (out->buf) memcpy( p, str, min( n, space ) * sizeof(WCHAR) );
55 #else
56 RtlUnicodeToMultiByteSize( &n, str, len * sizeof(WCHAR) );
57 if (out->buf) RtlUnicodeToMultiByteN( p, min( n, space ), NULL, str, len * sizeof(WCHAR) );
58 #endif
59 if (out->buf && space < n) /* overflow */
61 out->used = out->len;
62 return -1;
64 out->used += n;
65 return len;
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;
72 ULONG n;
74 if (len < 0) len = strlen( str );
76 #ifdef PRINTF_WIDE
77 RtlMultiByteToUnicodeSize( &n, str, len );
78 n /= sizeof(WCHAR);
79 if (out->buf) RtlMultiByteToUnicodeN( p, min( n, space ) * sizeof(WCHAR), NULL, str, len );
80 #else
81 n = len;
82 if (out->buf) memcpy( p, str, min( n, space ));
83 #endif
84 if (out->buf && space < n) /* overflow */
86 out->used = out->len;
87 return -1;
89 out->used += n;
90 return len;
93 static int FUNC_NAME(pf_output_string)( FUNC_NAME(pf_output) *out, const APICHAR *str, int len )
95 #ifdef PRINTF_WIDE
96 return FUNC_NAME(pf_output_wstr)( out, str, len );
97 #else
98 return FUNC_NAME(pf_output_str)( out, str, len );
99 #endif
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 )
105 int i, r = 0;
107 if (flags->Sign && !(flags->Format == 'd' || flags->Format == 'i')) flags->Sign = 0;
109 if (flags->Sign)
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 );
126 return r;
129 static int FUNC_NAME(pf_fill_right)( FUNC_NAME(pf_output) *out, int len, pf_flags *flags )
131 int i, r = 0;
132 APICHAR ch = ' ';
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 );
138 return r;
141 static int FUNC_NAME(pf_output_format_wstr)( FUNC_NAME(pf_output) *out, const wchar_t *str, int len,
142 pf_flags *flags )
144 int r = 0;
146 if (len < 0)
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 );
161 return r;
164 static int FUNC_NAME(pf_output_format_str)( FUNC_NAME(pf_output) *out, const char *str, int len,
165 pf_flags *flags )
167 int r = 0;
169 if (len < 0)
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 );
184 return r;
187 static int FUNC_NAME(pf_output_format)( FUNC_NAME(pf_output) *out, const APICHAR *str, int len,
188 pf_flags *flags )
190 #ifdef PRINTF_WIDE
191 return FUNC_NAME(pf_output_format_wstr)( out, str, len, flags );
192 #else
193 return FUNC_NAME(pf_output_format_str)( out, str, len, flags );
194 #endif
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);
212 #ifdef PRINTF_WIDE
213 return FUNC_NAME(pf_output_format_str)( out, str, len, flags );
214 #else
215 return FUNC_NAME(pf_output_format_wstr)( out, str, len, flags );
216 #endif
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 )
223 unsigned int base;
224 const APICHAR *digits;
225 int i, j, k;
227 if( flags->Format == 'o' )
228 base = 8;
229 else if( flags->Format == 'x' || flags->Format == 'X' )
230 base = 16;
231 else
232 base = 10;
234 if( flags->Format == 'X' )
235 digits = APISTR("0123456789ABCDEFX");
236 else
237 digits = APISTR("0123456789abcdefx");
239 if( x < 0 && ( flags->Format == 'd' || flags->Format == 'i' ) )
241 x = -x;
242 flags->Sign = '-';
245 i = 0;
246 if( x == 0 )
248 flags->Alternate = FALSE;
249 if( flags->Precision )
250 buf[i++] = '0';
252 else
253 while( x != 0 )
255 j = (ULONGLONG) x % base;
256 x = (ULONGLONG) x / base;
257 buf[i++] = digits[j];
259 k = flags->Precision - i;
260 while( k-- > 0 )
261 buf[i++] = '0';
262 if( flags->Alternate )
264 if( base == 16 )
266 buf[i++] = digits[16];
267 buf[i++] = '0';
269 else if( base == 8 && buf[i-1] != '0' )
270 buf[i++] = '0';
273 /* Adjust precision so pf_fill won't truncate the number later */
274 flags->Precision = i;
276 buf[i] = '\0';
277 j = 0;
278 while(--i > j) {
279 APICHAR tmp = buf[j];
280 buf[j] = buf[i];
281 buf[i] = tmp;
282 j++;
286 static int FUNC_NAME(pf_vsnprintf)( FUNC_NAME(pf_output) *out, const APICHAR *format, va_list valist )
288 int r;
289 const APICHAR *q, *p = format;
290 pf_flags flags;
292 while (*p)
294 for (q = p; *q; q++) if (*q == '%') break;
296 if (q != p)
298 r = FUNC_NAME(pf_output_string)(out, p, q - p);
299 if (r < 0) return r;
300 p = q;
301 if (!*p) break;
303 p++;
305 /* output a single % character */
306 if( *p == '%' )
308 r = FUNC_NAME(pf_output_string)(out, p++, 1);
309 if( r<0 )
310 return r;
311 continue;
314 /* parse the flags */
315 memset( &flags, 0, sizeof flags );
316 while (*p)
318 if( *p == '+' || *p == ' ' )
320 if ( flags.Sign != '+' )
321 flags.Sign = *p;
323 else if( *p == '-' )
324 flags.LeftAlign = TRUE;
325 else if( *p == '0' )
326 flags.PadZero = TRUE;
327 else if( *p == '#' )
328 flags.Alternate = TRUE;
329 else
330 break;
331 p++;
334 /* deal with the field width specifier */
335 flags.FieldLength = 0;
336 if( *p == '*' )
338 flags.FieldLength = va_arg( valist, int );
339 if (flags.FieldLength < 0)
341 flags.LeftAlign = TRUE;
342 flags.FieldLength = -flags.FieldLength;
344 p++;
346 else while (*p >= '0' && *p <= '9')
348 flags.FieldLength *= 10;
349 flags.FieldLength += *p++ - '0';
352 /* deal with precision */
353 flags.Precision = -1;
354 if( *p == '.' )
356 flags.Precision = 0;
357 p++;
358 if( *p == '*' )
360 flags.Precision = va_arg( valist, int );
361 p++;
363 else while (*p >= '0' && *p <= '9')
365 flags.Precision *= 10;
366 flags.Precision += *p++ - '0';
370 /* deal with integer width modifier */
371 while( *p )
373 if (*p == 'l' && *(p+1) == 'l')
375 flags.IntegerDouble = TRUE;
376 p += 2;
378 else if( *p == 'l' )
380 flags.IntegerLength = LEN_LONG;
381 p++;
383 else if( *p == 'L' )
385 p++;
387 else if( *p == 'h')
389 flags.IntegerLength = LEN_SHORT;
390 p++;
392 else if( *p == 'I' )
394 if( *(p+1) == '6' && *(p+2) == '4' )
396 flags.IntegerDouble = TRUE;
397 p += 3;
399 else if( *(p+1) == '3' && *(p+2) == '2' )
400 p += 3;
401 else if( p[1] && strchr( "diouxX", p[1] ) )
403 if( sizeof(void *) == 8 )
404 flags.IntegerDouble = TRUE;
405 p++;
407 else if ((p[1] >= '0' && p[1] <= '9') || !p[1])
408 break;
409 else
410 p++;
412 else if( *p == 'w' )
414 flags.WideString = TRUE;
415 p++;
417 else if ((*p == 'z' || *p == 't') && p[1] && strchr("diouxX", p[1]))
419 flags.IntegerNative = TRUE;
420 p++;
422 else if (*p == 'j')
424 flags.IntegerDouble = TRUE;
425 p++;
427 else if( *p == 'F' )
428 p++; /* ignore */
429 else
430 break;
433 flags.Format = *p;
434 r = 0;
436 if (flags.Format == '$')
438 FIXME("Positional parameters are not supported (%s)\n", FUNC_NAME(wine_dbgstr)(format));
439 return -1;
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' )
456 APICHAR pointer[32];
457 void *ptr = va_arg( valist, void * );
458 int prec = flags.Precision;
459 flags.Format = 'X';
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 );
468 /* deal with %n */
469 else if( flags.Format == 'n' )
471 int *x = va_arg(valist, int *);
472 *x = out->used;
474 else if( flags.Format && strchr("diouxX", flags.Format ))
476 APICHAR number[40], *x = number;
477 int max_len;
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) );
493 else
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 );
498 if( x != number )
499 RtlFreeHeap( GetProcessHeap(), 0, x );
501 else
502 continue;
504 if( r<0 )
505 return r;
506 p++;
508 return out->used;
511 #undef APICHAR
512 #undef APISTR
513 #undef FUNC_NAME