1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | /*++ |
6 | |
7 | |
8 | |
9 | Module Name: |
10 | |
11 | printfcpp.cpp |
12 | |
13 | Abstract: |
14 | |
15 | Implementation of suspension safe printf functions. |
16 | |
17 | Revision History: |
18 | |
19 | |
20 | |
21 | --*/ |
22 | |
23 | #include "pal/corunix.hpp" |
24 | #include "pal/thread.hpp" |
25 | #include "pal/malloc.hpp" |
26 | #include "pal/file.hpp" |
27 | #include "pal/printfcpp.hpp" |
28 | #include "pal/palinternal.h" |
29 | #include "pal/dbgmsg.h" |
30 | #include "pal/cruntime.h" |
31 | |
32 | #include <errno.h> |
33 | |
34 | SET_DEFAULT_DEBUG_CHANNEL(CRT); |
35 | |
36 | using namespace CorUnix; |
37 | |
38 | static const char __nullstring[] = "(null)" ; /* string to print on null ptr */ |
39 | static const WCHAR __wnullstring[] = W("(null)" ); /* string to print on null ptr */ |
40 | |
41 | int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap); |
42 | int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list ap); |
43 | |
44 | extern "C" |
45 | { |
46 | |
47 | /******************************************************************************* |
48 | Function: |
49 | Internal_Convertfwrite |
50 | This function is a wrapper around fwrite for cases where the buffer has |
51 | to be converted from WideChar to MultiByte |
52 | *******************************************************************************/ |
53 | |
54 | static int Internal_Convertfwrite(CPalThread *pthrCurrent, const void *buffer, size_t size, size_t count, FILE *stream, BOOL convert) |
55 | { |
56 | int ret; |
57 | int iError = 0; |
58 | |
59 | #if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL |
60 | clearerr (stream); |
61 | #endif |
62 | |
63 | if(convert) |
64 | { |
65 | int nsize; |
66 | LPSTR newBuff = 0; |
67 | nsize = WideCharToMultiByte(CP_ACP, 0,(LPCWSTR)buffer, count, 0, 0, 0, 0); |
68 | if (!nsize) |
69 | { |
70 | ASSERT("WideCharToMultiByte failed. Error is %d\n" , GetLastError()); |
71 | return -1; |
72 | } |
73 | newBuff = (LPSTR) InternalMalloc(nsize); |
74 | if (!newBuff) |
75 | { |
76 | ERROR("InternalMalloc failed\n" ); |
77 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
78 | return -1; |
79 | } |
80 | nsize = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)buffer, count, newBuff, nsize, 0, 0); |
81 | if (!nsize) |
82 | { |
83 | ASSERT("WideCharToMultiByte failed. Error is %d\n" , GetLastError()); |
84 | free(newBuff); |
85 | return -1; |
86 | } |
87 | ret = InternalFwrite(newBuff, 1, count, stream, &iError); |
88 | if (iError != 0) |
89 | { |
90 | ERROR("InternalFwrite did not write the whole buffer. Error is %d\n" , iError); |
91 | free(newBuff); |
92 | return -1; |
93 | } |
94 | free(newBuff); |
95 | } |
96 | else |
97 | { |
98 | ret = InternalFwrite(buffer, size, count, stream, &iError); |
99 | if (iError != 0) |
100 | { |
101 | ERROR("InternalFwrite did not write the whole buffer. Error is %d\n" , iError); |
102 | return -1; |
103 | } |
104 | } |
105 | return ret; |
106 | |
107 | } |
108 | |
109 | /******************************************************************************* |
110 | Function: |
111 | Internal_ExtractFormatA |
112 | |
113 | Paramaters: |
114 | Fmt |
115 | - format string to parse |
116 | - first character must be a '%' |
117 | - paramater gets updated to point to the character after |
118 | the %<foo> format string |
119 | Out |
120 | - buffer will contain the %<foo> format string |
121 | Flags |
122 | - paramater will be set with the PRINTF_FORMAT_FLAGS defined above |
123 | Width |
124 | - will contain the width specified by the format string |
125 | - -1 if none given |
126 | Precision |
127 | - will contain the precision specified in the format string |
128 | - -1 if none given |
129 | Prefix |
130 | - an enumeration of the type prefix |
131 | Type |
132 | - an enumeration of the type value |
133 | |
134 | Notes: |
135 | - I'm also handling the undocumented %ws, %wc, %w... |
136 | - %#10x, when we have a width greater than the length (i.e padding) the |
137 | length of the padding is not consistent with MS's wsprintf |
138 | (MS adds an extra 2 padding chars, length of "0x") |
139 | - MS's wsprintf seems to ingore a 'h' prefix for number types |
140 | - MS's "%p" is different than gcc's |
141 | e.g. printf("%p", NULL); |
142 | MS --> 00000000 |
143 | gcc --> 0x0 |
144 | - the length of the exponent (precision) for floating types is different |
145 | between MS and gcc |
146 | e.g. printf("%E", 256.0); |
147 | MS --> 2.560000E+002 |
148 | gcc --> 2.560000E+02 |
149 | *******************************************************************************/ |
150 | BOOL (CPalThread *pthrCurrent, LPCSTR *Fmt, LPSTR Out, LPINT Flags, |
151 | LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type) |
152 | { |
153 | BOOL Result = FALSE; |
154 | LPSTR TempStr; |
155 | LPSTR TempStrPtr; |
156 | |
157 | *Width = WIDTH_DEFAULT; |
158 | *Precision = PRECISION_DEFAULT; |
159 | *Flags = PFF_NONE; |
160 | *Prefix = PFF_PREFIX_DEFAULT; |
161 | *Type = PFF_TYPE_DEFAULT; |
162 | |
163 | if (*Fmt && **Fmt == '%') |
164 | { |
165 | *Out++ = *(*Fmt)++; |
166 | } |
167 | else |
168 | { |
169 | return Result; |
170 | } |
171 | |
172 | /* we'll never need a temp string longer than the original */ |
173 | TempStrPtr = TempStr = (LPSTR) InternalMalloc(strlen(*Fmt)+1); |
174 | if (!TempStr) |
175 | { |
176 | ERROR("InternalMalloc failed\n" ); |
177 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
178 | return Result; |
179 | } |
180 | |
181 | /* parse flags */ |
182 | while (**Fmt && (**Fmt == '-' || **Fmt == '+' || |
183 | **Fmt == '0' || **Fmt == ' ' || **Fmt == '#')) |
184 | { |
185 | switch (**Fmt) |
186 | { |
187 | case '-': |
188 | *Flags |= PFF_MINUS; break; |
189 | case '+': |
190 | *Flags |= PFF_PLUS; break; |
191 | case '0': |
192 | *Flags |= PFF_ZERO; break; |
193 | case ' ': |
194 | *Flags |= PFF_SPACE; break; |
195 | case '#': |
196 | *Flags |= PFF_POUND; break; |
197 | } |
198 | *Out++ = *(*Fmt)++; |
199 | } |
200 | /* '-' flag negates '0' flag */ |
201 | if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO)) |
202 | { |
203 | *Flags -= PFF_ZERO; |
204 | } |
205 | |
206 | /* grab width specifier */ |
207 | if (isdigit((unsigned char) **Fmt)) |
208 | { |
209 | TempStrPtr = TempStr; |
210 | while (isdigit((unsigned char) **Fmt)) |
211 | { |
212 | *TempStrPtr++ = **Fmt; |
213 | *Out++ = *(*Fmt)++; |
214 | } |
215 | *TempStrPtr = 0; /* end string */ |
216 | *Width = atoi(TempStr); |
217 | if (*Width < 0) |
218 | { |
219 | ERROR("atoi returned a negative value indicative of an overflow.\n" ); |
220 | pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); |
221 | return Result; |
222 | } |
223 | } |
224 | else if (**Fmt == '*') |
225 | { |
226 | *Width = WIDTH_STAR; |
227 | *Out++ = *(*Fmt)++; |
228 | if (isdigit((unsigned char) **Fmt)) |
229 | { |
230 | /* this is an invalid width because we have a * then a number */ |
231 | /* printf handles this by just printing the whole string */ |
232 | *Width = WIDTH_INVALID; |
233 | while (isdigit((unsigned char) **Fmt)) |
234 | { |
235 | *Out++ = *(*Fmt)++; |
236 | } |
237 | } |
238 | } |
239 | |
240 | |
241 | /* grab precision specifier */ |
242 | if (**Fmt == '.') |
243 | { |
244 | *Out++ = *(*Fmt)++; |
245 | if (isdigit((unsigned char) **Fmt)) |
246 | { |
247 | TempStrPtr = TempStr; |
248 | while (isdigit((unsigned char) **Fmt)) |
249 | { |
250 | *TempStrPtr++ = **Fmt; |
251 | *Out++ = *(*Fmt)++; |
252 | } |
253 | *TempStrPtr = 0; /* end string */ |
254 | *Precision = atoi(TempStr); |
255 | if (*Precision < 0) |
256 | { |
257 | ERROR("atoi returned a negative value indicative of an overflow.\n" ); |
258 | pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); |
259 | return Result; |
260 | } |
261 | } |
262 | else if (**Fmt == '*') |
263 | { |
264 | *Precision = PRECISION_STAR; |
265 | *Out++ = *(*Fmt)++; |
266 | if (isdigit((unsigned char) **Fmt)) |
267 | { |
268 | /* this is an invalid precision because we have a .* then a number */ |
269 | /* printf handles this by just printing the whole string */ |
270 | *Precision = PRECISION_INVALID; |
271 | while (isdigit((unsigned char) **Fmt)) |
272 | { |
273 | *Out++ = *(*Fmt)++; |
274 | } |
275 | } |
276 | } |
277 | else |
278 | { |
279 | *Precision = PRECISION_DOT; |
280 | } |
281 | } |
282 | |
283 | #ifdef BIT64 |
284 | if (**Fmt == 'p') |
285 | { |
286 | *Prefix = PFF_PREFIX_LONGLONG; |
287 | } |
288 | #endif |
289 | if ((*Fmt)[0] == 'I') |
290 | { |
291 | /* grab prefix of 'I64' for __int64 */ |
292 | if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4') |
293 | { |
294 | /* convert to 'll' so that Unix snprintf can handle it */ |
295 | *Fmt += 3; |
296 | *Prefix = PFF_PREFIX_LONGLONG; |
297 | } |
298 | /* grab prefix of 'I32' for __int32 */ |
299 | else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2') |
300 | { |
301 | *Fmt += 3; |
302 | } |
303 | else |
304 | { |
305 | ++(*Fmt); |
306 | #ifdef BIT64 |
307 | /* convert to 'll' so that Unix snprintf can handle it */ |
308 | *Prefix = PFF_PREFIX_LONGLONG; |
309 | #endif |
310 | } |
311 | } |
312 | /* grab a prefix of 'h' */ |
313 | else if (**Fmt == 'h') |
314 | { |
315 | *Prefix = PFF_PREFIX_SHORT; |
316 | ++(*Fmt); |
317 | } |
318 | /* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */ |
319 | else if (**Fmt == 'l' || **Fmt == 'w') |
320 | { |
321 | ++(*Fmt); |
322 | #ifdef BIT64 |
323 | // Only want to change the prefix on 64 bit when printing characters. |
324 | if (**Fmt == 'c' || **Fmt == 's') |
325 | #endif |
326 | { |
327 | *Prefix = PFF_PREFIX_LONG; |
328 | } |
329 | if (**Fmt == 'l') |
330 | { |
331 | *Prefix = PFF_PREFIX_LONGLONG; |
332 | ++(*Fmt); |
333 | } |
334 | } |
335 | else if (**Fmt == 'L') |
336 | { |
337 | /* a prefix of 'L' seems to be ignored */ |
338 | ++(*Fmt); |
339 | } |
340 | |
341 | /* grab type 'c' */ |
342 | if (**Fmt == 'c' || **Fmt == 'C') |
343 | { |
344 | *Type = PFF_TYPE_CHAR; |
345 | if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'C') |
346 | { |
347 | *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ |
348 | } |
349 | if (*Prefix == PFF_PREFIX_LONG) |
350 | { |
351 | *Out++ = 'l'; |
352 | } |
353 | *Out++ = 'c'; |
354 | ++(*Fmt); |
355 | Result = TRUE; |
356 | } |
357 | /* grab type 's' */ |
358 | else if (**Fmt == 's' || **Fmt == 'S') |
359 | { |
360 | *Type = PFF_TYPE_STRING; |
361 | if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'S') |
362 | { |
363 | *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ |
364 | } |
365 | if (*Prefix == PFF_PREFIX_LONG) |
366 | { |
367 | *Out++ = 'l'; |
368 | } |
369 | *Out++ = 's'; |
370 | ++(*Fmt); |
371 | Result = TRUE; |
372 | } |
373 | /* grab int types */ |
374 | else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' || |
375 | **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X') |
376 | { |
377 | *Type = PFF_TYPE_INT; |
378 | if (*Prefix == PFF_PREFIX_SHORT) |
379 | { |
380 | *Out++ = 'h'; |
381 | } |
382 | else if (*Prefix == PFF_PREFIX_LONG) |
383 | { |
384 | *Out++ = 'l'; |
385 | } |
386 | else if (*Prefix == PFF_PREFIX_LONGLONG) |
387 | { |
388 | *Out++ = 'l'; |
389 | *Out++ = 'l'; |
390 | } |
391 | *Out++ = *(*Fmt)++; |
392 | Result = TRUE; |
393 | } |
394 | else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' || |
395 | **Fmt == 'g' || **Fmt == 'G') |
396 | { |
397 | /* we can safely ignore the prefixes and only add the type*/ |
398 | *Type = PFF_TYPE_FLOAT; |
399 | *Out++ = *(*Fmt)++; |
400 | Result = TRUE; |
401 | } |
402 | else if (**Fmt == 'n') |
403 | { |
404 | if (*Prefix == PFF_PREFIX_SHORT) |
405 | { |
406 | *Out++ = 'h'; |
407 | } |
408 | *Out++ = *(*Fmt)++; |
409 | *Type = PFF_TYPE_N; |
410 | Result = TRUE; |
411 | } |
412 | else if (**Fmt == 'p') |
413 | { |
414 | *Type = PFF_TYPE_P; |
415 | (*Fmt)++; |
416 | |
417 | if (*Prefix == PFF_PREFIX_LONGLONG) |
418 | { |
419 | if (*Precision == PRECISION_DEFAULT) |
420 | { |
421 | *Precision = 16; |
422 | *Out++ = '.'; |
423 | *Out++ = '1'; |
424 | *Out++ = '6'; |
425 | } |
426 | /* native *printf does not support %I64p |
427 | (actually %llp), so we need to cheat a little bit */ |
428 | *Out++ = 'l'; |
429 | *Out++ = 'l'; |
430 | } |
431 | else |
432 | { |
433 | if (*Precision == PRECISION_DEFAULT) |
434 | { |
435 | *Precision = 8; |
436 | *Out++ = '.'; |
437 | *Out++ = '8'; |
438 | } |
439 | } |
440 | *Out++ = 'X'; |
441 | Result = TRUE; |
442 | } |
443 | |
444 | *Out = 0; /* end the string */ |
445 | free(TempStr); |
446 | return Result; |
447 | } |
448 | |
449 | /******************************************************************************* |
450 | Function: |
451 | Internal_ExtractFormatW |
452 | |
453 | -- see Internal_ExtractFormatA above |
454 | *******************************************************************************/ |
455 | BOOL (CPalThread *pthrCurrent, LPCWSTR *Fmt, LPSTR Out, LPINT Flags, |
456 | LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type) |
457 | { |
458 | BOOL Result = FALSE; |
459 | LPSTR TempStr; |
460 | LPSTR TempStrPtr; |
461 | |
462 | *Width = WIDTH_DEFAULT; |
463 | *Precision = PRECISION_DEFAULT; |
464 | *Flags = PFF_NONE; |
465 | *Prefix = PFF_PREFIX_DEFAULT; |
466 | *Type = PFF_TYPE_DEFAULT; |
467 | |
468 | if (*Fmt && **Fmt == '%') |
469 | { |
470 | *Out++ = (CHAR) *(*Fmt)++; |
471 | } |
472 | else |
473 | { |
474 | return Result; |
475 | } |
476 | |
477 | /* we'll never need a temp string longer than the original */ |
478 | TempStrPtr = TempStr = (LPSTR) InternalMalloc(PAL_wcslen(*Fmt)+1); |
479 | if (!TempStr) |
480 | { |
481 | ERROR("InternalMalloc failed\n" ); |
482 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
483 | return Result; |
484 | } |
485 | |
486 | /* parse flags */ |
487 | while (**Fmt && (**Fmt == '-' || **Fmt == '+' || |
488 | **Fmt == '0' || **Fmt == ' ' || **Fmt == '#')) |
489 | { |
490 | switch (**Fmt) |
491 | { |
492 | case '-': |
493 | *Flags |= PFF_MINUS; break; |
494 | case '+': |
495 | *Flags |= PFF_PLUS; break; |
496 | case '0': |
497 | *Flags |= PFF_ZERO; break; |
498 | case ' ': |
499 | *Flags |= PFF_SPACE; break; |
500 | case '#': |
501 | *Flags |= PFF_POUND; break; |
502 | } |
503 | *Out++ = (CHAR) *(*Fmt)++; |
504 | } |
505 | /* '-' flag negates '0' flag */ |
506 | if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO)) |
507 | { |
508 | *Flags -= PFF_ZERO; |
509 | } |
510 | |
511 | /* grab width specifier */ |
512 | if (isdigit(**Fmt)) |
513 | { |
514 | TempStrPtr = TempStr; |
515 | while (isdigit(**Fmt)) |
516 | { |
517 | *TempStrPtr++ = (CHAR) **Fmt; |
518 | *Out++ = (CHAR) *(*Fmt)++; |
519 | } |
520 | *TempStrPtr = 0; /* end string */ |
521 | *Width = atoi(TempStr); |
522 | if (*Width < 0) |
523 | { |
524 | ERROR("atoi returned a negative value indicative of an overflow.\n" ); |
525 | pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); |
526 | return Result; |
527 | } |
528 | } |
529 | else if (**Fmt == '*') |
530 | { |
531 | *Width = WIDTH_STAR; |
532 | *Out++ = (CHAR) *(*Fmt)++; |
533 | if (isdigit(**Fmt)) |
534 | { |
535 | /* this is an invalid width because we have a * then a number */ |
536 | /* printf handles this by just printing the whole string */ |
537 | *Width = WIDTH_INVALID; |
538 | while (isdigit(**Fmt)) |
539 | { |
540 | *Out++ = (CHAR) *(*Fmt)++; |
541 | } |
542 | } |
543 | } |
544 | |
545 | /* grab precision specifier */ |
546 | if (**Fmt == '.') |
547 | { |
548 | *Out++ = (CHAR) *(*Fmt)++; |
549 | if (isdigit(**Fmt)) |
550 | { |
551 | TempStrPtr = TempStr; |
552 | while (isdigit(**Fmt)) |
553 | { |
554 | *TempStrPtr++ = (CHAR) **Fmt; |
555 | *Out++ = (CHAR) *(*Fmt)++; |
556 | } |
557 | *TempStrPtr = 0; /* end string */ |
558 | *Precision = atoi(TempStr); |
559 | if (*Precision < 0) |
560 | { |
561 | ERROR("atoi returned a negative value indicative of an overflow.\n" ); |
562 | pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); |
563 | return Result; |
564 | } |
565 | } |
566 | else if (**Fmt == '*') |
567 | { |
568 | *Precision = PRECISION_STAR; |
569 | *Out++ = (CHAR) *(*Fmt)++; |
570 | if (isdigit(**Fmt)) |
571 | { |
572 | /* this is an invalid precision because we have a .* then a number */ |
573 | /* printf handles this by just printing the whole string */ |
574 | *Precision = PRECISION_INVALID; |
575 | while (isdigit(**Fmt)) |
576 | { |
577 | *Out++ = (CHAR) *(*Fmt)++; |
578 | } |
579 | } |
580 | } |
581 | else |
582 | { |
583 | *Precision = PRECISION_DOT; |
584 | } |
585 | } |
586 | |
587 | #ifdef BIT64 |
588 | if (**Fmt == 'p') |
589 | { |
590 | *Prefix = PFF_PREFIX_LONGLONG; |
591 | } |
592 | #endif |
593 | if ((*Fmt)[0] == 'I') |
594 | { |
595 | /* grab prefix of 'I64' for __int64 */ |
596 | if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4') |
597 | { |
598 | /* convert to 'll' so that Unix snprintf can handle it */ |
599 | *Fmt += 3; |
600 | *Prefix = PFF_PREFIX_LONGLONG; |
601 | } |
602 | /* grab prefix of 'I32' for __int32 */ |
603 | else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2') |
604 | { |
605 | *Fmt += 3; |
606 | } |
607 | else |
608 | { |
609 | ++(*Fmt); |
610 | #ifdef BIT64 |
611 | /* convert to 'll' so that Unix snprintf can handle it */ |
612 | *Prefix = PFF_PREFIX_LONGLONG; |
613 | #endif |
614 | } |
615 | } |
616 | /* grab a prefix of 'h' */ |
617 | else if (**Fmt == 'h') |
618 | { |
619 | *Prefix = PFF_PREFIX_SHORT; |
620 | ++(*Fmt); |
621 | } |
622 | else if (**Fmt == 'l' || **Fmt == 'w') |
623 | { |
624 | ++(*Fmt); |
625 | #ifdef BIT64 |
626 | // Only want to change the prefix on 64 bit when printing characters. |
627 | if (**Fmt == 'C' || **Fmt == 'S') |
628 | #endif |
629 | { |
630 | *Prefix = PFF_PREFIX_LONG_W; |
631 | } |
632 | if (**Fmt == 'l') |
633 | { |
634 | *Prefix = PFF_PREFIX_LONGLONG; |
635 | ++(*Fmt); |
636 | } |
637 | } |
638 | else if (**Fmt == 'L') |
639 | { |
640 | /* a prefix of 'L' seems to be ignored */ |
641 | ++(*Fmt); |
642 | } |
643 | |
644 | |
645 | /* grab type 'c' */ |
646 | if (**Fmt == 'c' || **Fmt == 'C') |
647 | { |
648 | *Type = PFF_TYPE_CHAR; |
649 | if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'c') |
650 | { |
651 | *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ |
652 | } |
653 | if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W) |
654 | { |
655 | *Out++ = 'l'; |
656 | *Prefix = PFF_PREFIX_LONG; |
657 | } |
658 | *Out++ = 'c'; |
659 | ++(*Fmt); |
660 | Result = TRUE; |
661 | } |
662 | /* grab type 's' */ |
663 | else if (**Fmt == 's' || **Fmt == 'S' ) |
664 | { |
665 | if ( **Fmt == 'S' ) |
666 | { |
667 | *Type = PFF_TYPE_WSTRING; |
668 | } |
669 | else |
670 | { |
671 | *Type = PFF_TYPE_STRING; |
672 | } |
673 | if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 's') |
674 | { |
675 | *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ |
676 | } |
677 | if (*Prefix == PFF_PREFIX_LONG) |
678 | { |
679 | *Out++ = 'l'; |
680 | } |
681 | |
682 | *Out++ = 's'; |
683 | ++(*Fmt); |
684 | Result = TRUE; |
685 | } |
686 | /* grab int types */ |
687 | else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' || |
688 | **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X') |
689 | { |
690 | *Type = PFF_TYPE_INT; |
691 | if (*Prefix == PFF_PREFIX_SHORT) |
692 | { |
693 | *Out++ = 'h'; |
694 | } |
695 | else if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W) |
696 | { |
697 | *Out++ = 'l'; |
698 | *Prefix = PFF_PREFIX_LONG; |
699 | } |
700 | else if (*Prefix == PFF_PREFIX_LONGLONG) |
701 | { |
702 | *Out++ = 'l'; |
703 | *Out++ = 'l'; |
704 | } |
705 | *Out++ = *(*Fmt)++; |
706 | Result = TRUE; |
707 | } |
708 | else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' || |
709 | **Fmt == 'g' || **Fmt == 'G') |
710 | { |
711 | /* we can safely ignore the prefixes and only add the type*/ |
712 | if (*Prefix == PFF_PREFIX_LONG_W) |
713 | { |
714 | *Prefix = PFF_PREFIX_LONG; |
715 | } |
716 | |
717 | *Type = PFF_TYPE_FLOAT; |
718 | *Out++ = *(*Fmt)++; |
719 | Result = TRUE; |
720 | } |
721 | else if (**Fmt == 'n') |
722 | { |
723 | if (*Prefix == PFF_PREFIX_LONG_W) |
724 | { |
725 | *Prefix = PFF_PREFIX_LONG; |
726 | } |
727 | |
728 | if (*Prefix == PFF_PREFIX_SHORT) |
729 | { |
730 | *Out++ = 'h'; |
731 | } |
732 | *Out++ = *(*Fmt)++; |
733 | *Type = PFF_TYPE_N; |
734 | Result = TRUE; |
735 | } |
736 | else if (**Fmt == 'p') |
737 | { |
738 | *Type = PFF_TYPE_P; |
739 | (*Fmt)++; |
740 | |
741 | if (*Prefix == PFF_PREFIX_LONGLONG) |
742 | { |
743 | if (*Precision == PRECISION_DEFAULT) |
744 | { |
745 | *Precision = 16; |
746 | *Out++ = '.'; |
747 | *Out++ = '1'; |
748 | *Out++ = '6'; |
749 | } |
750 | /* native *printf does not support %I64p |
751 | (actually %llp), so we need to cheat a little bit */ |
752 | *Out++ = 'l'; |
753 | *Out++ = 'l'; |
754 | } |
755 | else |
756 | { |
757 | if (*Precision == PRECISION_DEFAULT) |
758 | { |
759 | *Precision = 8; |
760 | *Out++ = '.'; |
761 | *Out++ = '8'; |
762 | } |
763 | if (*Prefix == PFF_PREFIX_LONG_W) |
764 | { |
765 | *Prefix = PFF_PREFIX_LONG; |
766 | } |
767 | } |
768 | *Out++ = 'X'; |
769 | Result = TRUE; |
770 | } |
771 | |
772 | *Out = 0; /* end the string */ |
773 | free(TempStr); |
774 | return Result; |
775 | } |
776 | |
777 | /******************************************************************************* |
778 | Function: |
779 | Internal_AddPaddingVfprintf |
780 | |
781 | Parameters: |
782 | stream |
783 | - file stream to place padding and given string (In) |
784 | In |
785 | - string to place into (Out) accompanied with padding |
786 | Padding |
787 | - number of padding chars to add |
788 | Flags |
789 | - padding style flags (PRINTF_FORMAT_FLAGS) |
790 | *******************************************************************************/ |
791 | |
792 | INT Internal_AddPaddingVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPCSTR In, |
793 | INT Padding, INT Flags) |
794 | { |
795 | LPSTR Out; |
796 | INT LengthInStr; |
797 | INT Length; |
798 | LPSTR OutOriginal; |
799 | INT Written; |
800 | |
801 | LengthInStr = strlen(In); |
802 | Length = LengthInStr; |
803 | |
804 | if (Padding > 0) |
805 | { |
806 | Length += Padding; |
807 | } |
808 | Out = (LPSTR) InternalMalloc(Length+1); |
809 | int iLength = Length+1; |
810 | if (!Out) |
811 | { |
812 | ERROR("InternalMalloc failed\n" ); |
813 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
814 | return -1; |
815 | } |
816 | OutOriginal = Out; |
817 | |
818 | if (Flags & PFF_MINUS) /* pad on right */ |
819 | { |
820 | if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS) |
821 | { |
822 | ERROR("strcpy_s failed\n" ); |
823 | pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); |
824 | Written = -1; |
825 | goto Done; |
826 | } |
827 | |
828 | Out += LengthInStr; |
829 | iLength -= LengthInStr; |
830 | } |
831 | if (Padding > 0) |
832 | { |
833 | iLength -= Padding; |
834 | if (Flags & PFF_ZERO) /* '0', pad with zeros */ |
835 | { |
836 | while (Padding--) |
837 | { |
838 | *Out++ = '0'; |
839 | } |
840 | } |
841 | else /* pad with spaces */ |
842 | { |
843 | while (Padding--) |
844 | { |
845 | *Out++ = ' '; |
846 | } |
847 | } |
848 | } |
849 | if (!(Flags & PFF_MINUS)) /* put 'In' after padding */ |
850 | { |
851 | if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS) |
852 | { |
853 | ERROR("strcpy_s failed\n" ); |
854 | pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); |
855 | Written = -1; |
856 | goto Done; |
857 | } |
858 | |
859 | Out += LengthInStr; |
860 | iLength -= LengthInStr; |
861 | } |
862 | |
863 | #if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL |
864 | clearerr (stream->bsdFilePtr); |
865 | #endif |
866 | |
867 | Written = InternalFwrite(OutOriginal, 1, Length, stream->bsdFilePtr, &stream->PALferrorCode); |
868 | if (stream->PALferrorCode == PAL_FILE_ERROR) |
869 | { |
870 | ERROR("fwrite() failed with errno == %d\n" , errno); |
871 | } |
872 | |
873 | Done: |
874 | free(OutOriginal); |
875 | |
876 | return Written; |
877 | } |
878 | |
879 | /******************************************************************************* |
880 | Function: |
881 | Internal_AddPaddingVfwprintf |
882 | |
883 | Parameters: |
884 | stream |
885 | - file stream to place padding and given string (In) |
886 | In |
887 | - string to place into (Out) accompanied with padding |
888 | Padding |
889 | - number of padding chars to add |
890 | Flags |
891 | - padding style flags (PRINTF_FORMAT_FLAGS) |
892 | *******************************************************************************/ |
893 | static INT Internal_AddPaddingVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPWSTR In, |
894 | INT Padding, INT Flags,BOOL convert) |
895 | { |
896 | LPWSTR Out; |
897 | LPWSTR OutOriginal; |
898 | INT LengthInStr; |
899 | INT Length; |
900 | INT Written = 0; |
901 | |
902 | LengthInStr = PAL_wcslen(In); |
903 | Length = LengthInStr; |
904 | |
905 | if (Padding > 0) |
906 | { |
907 | Length += Padding; |
908 | } |
909 | |
910 | int iLen = (Length+1); |
911 | Out = (LPWSTR) InternalMalloc(iLen * sizeof(WCHAR)); |
912 | if (!Out) |
913 | { |
914 | ERROR("InternalMalloc failed\n" ); |
915 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
916 | return -1; |
917 | } |
918 | OutOriginal = Out; |
919 | |
920 | if (Flags & PFF_MINUS) /* pad on right */ |
921 | { |
922 | if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS) |
923 | { |
924 | ERROR("wcscpy_s failed!\n" ); |
925 | free(OutOriginal); |
926 | pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); |
927 | return -1; |
928 | } |
929 | Out += LengthInStr; |
930 | iLen -= LengthInStr; |
931 | } |
932 | if (Padding > 0) |
933 | { |
934 | iLen -= Padding; |
935 | if (Flags & PFF_ZERO) /* '0', pad with zeros */ |
936 | { |
937 | while (Padding--) |
938 | { |
939 | *Out++ = '0'; |
940 | } |
941 | } |
942 | else /* pad with spaces */ |
943 | { |
944 | while (Padding--) |
945 | { |
946 | *Out++ = ' '; |
947 | } |
948 | } |
949 | } |
950 | if (!(Flags & PFF_MINUS)) /* put 'In' after padding */ |
951 | { |
952 | if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS) |
953 | { |
954 | ERROR("wcscpy_s failed!\n" ); |
955 | free(OutOriginal); |
956 | pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); |
957 | return -1; |
958 | } |
959 | |
960 | Out += LengthInStr; |
961 | iLen -= LengthInStr; |
962 | } |
963 | |
964 | if (Length > 0) { |
965 | Written = Internal_Convertfwrite(pthrCurrent, OutOriginal, sizeof(wchar_16), Length, |
966 | (FILE*)(stream->bsdFilePtr), convert); |
967 | |
968 | if (-1 == Written) |
969 | { |
970 | ERROR("fwrite() failed with errno == %d\n" , errno); |
971 | } |
972 | free(OutOriginal); |
973 | } |
974 | |
975 | return Written; |
976 | } |
977 | |
978 | /******************************************************************************* |
979 | Function: |
980 | PAL_vfprintf |
981 | |
982 | Parameters: |
983 | stream |
984 | - out stream |
985 | Format |
986 | - format string |
987 | ap |
988 | - stdarg parameter list |
989 | *******************************************************************************/ |
990 | |
991 | int __cdecl PAL_vfprintf(PAL_FILE *stream, const char *format, va_list ap) |
992 | { |
993 | return CoreVfprintf(InternalGetCurrentThread(), stream, format, ap); |
994 | } |
995 | |
996 | /******************************************************************************* |
997 | Function: |
998 | PAL_vfwprintf |
999 | |
1000 | Parameters: |
1001 | stream |
1002 | - out stream |
1003 | Format |
1004 | - format string |
1005 | ap |
1006 | - stdarg parameter list |
1007 | *******************************************************************************/ |
1008 | |
1009 | int __cdecl PAL_vfwprintf(PAL_FILE *stream, const wchar_16 *format, va_list ap) |
1010 | { |
1011 | return CoreVfwprintf(InternalGetCurrentThread(), stream, format, ap); |
1012 | } |
1013 | |
1014 | } // end extern "C" |
1015 | |
1016 | int CorUnix::InternalVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap) |
1017 | { |
1018 | return CoreVfprintf(pthrCurrent, stream, format, ap); |
1019 | } |
1020 | |
1021 | int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list aparg) |
1022 | { |
1023 | CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */ |
1024 | LPCWSTR Fmt = format; |
1025 | LPCWSTR TempWStr = NULL; |
1026 | LPWSTR AllocedTempWStr = NULL; |
1027 | LPWSTR WorkingWStr = NULL; |
1028 | WCHAR TempWChar[2]; |
1029 | INT Flags; |
1030 | INT Width; |
1031 | INT Precision; |
1032 | INT Prefix; |
1033 | INT Type; |
1034 | INT TempInt; |
1035 | int mbtowcResult; |
1036 | int written=0; |
1037 | int paddingReturnValue; |
1038 | int ret; |
1039 | va_list ap; |
1040 | |
1041 | /* fwprintf for now in the PAL is always used on file opened |
1042 | in text mode. In those case the output should be ANSI not Unicode */ |
1043 | BOOL textMode = TRUE; |
1044 | |
1045 | PERF_ENTRY(vfwprintf); |
1046 | ENTRY("vfwprintf (stream=%p, format=%p (%S))\n" , |
1047 | stream, format, format); |
1048 | |
1049 | va_copy(ap, aparg); |
1050 | |
1051 | while (*Fmt) |
1052 | { |
1053 | if(*Fmt == '%' && |
1054 | TRUE == Internal_ExtractFormatW(pthrCurrent, &Fmt, TempBuff, &Flags, |
1055 | &Width, &Precision, |
1056 | &Prefix, &Type)) |
1057 | { |
1058 | if (((Prefix == PFF_PREFIX_LONG || Prefix == PFF_PREFIX_LONG_W) && |
1059 | (Type == PFF_TYPE_STRING || Type == PFF_TYPE_WSTRING)) || |
1060 | (Type == PFF_TYPE_WSTRING && (Flags & PFF_ZERO) != 0)) |
1061 | { |
1062 | AllocedTempWStr = NULL; |
1063 | |
1064 | if (WIDTH_STAR == Width) |
1065 | { |
1066 | Width = va_arg(ap, INT); |
1067 | } |
1068 | else if (WIDTH_INVALID == Width) |
1069 | { |
1070 | /* both a '*' and a number, ignore, but remove arg */ |
1071 | TempInt = va_arg(ap, INT); /* value not used */ |
1072 | } |
1073 | |
1074 | if (PRECISION_STAR == Precision) |
1075 | { |
1076 | Precision = va_arg(ap, INT); |
1077 | } |
1078 | else if (PRECISION_INVALID == Precision) |
1079 | { |
1080 | /* both a '*' and a number, ignore, but remove arg */ |
1081 | TempInt = va_arg(ap, INT); /* value not used */ |
1082 | } |
1083 | |
1084 | if (Type == PFF_TYPE_STRING || Prefix == PFF_PREFIX_LONG_W) |
1085 | { |
1086 | TempWStr = va_arg(ap, LPWSTR); |
1087 | } |
1088 | else |
1089 | { |
1090 | /* %lS assumes a LPSTR argument. */ |
1091 | LPCSTR s = va_arg(ap, LPSTR ); |
1092 | if (s == NULL) |
1093 | { |
1094 | TempWStr = NULL; |
1095 | } |
1096 | else |
1097 | { |
1098 | UINT Length = 0; |
1099 | Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 ); |
1100 | if ( Length != 0 ) |
1101 | { |
1102 | AllocedTempWStr = |
1103 | (LPWSTR)InternalMalloc( (Length) * sizeof( WCHAR ) ); |
1104 | |
1105 | if ( AllocedTempWStr ) |
1106 | { |
1107 | MultiByteToWideChar( CP_ACP, 0, s, -1, |
1108 | AllocedTempWStr, Length ); |
1109 | TempWStr = AllocedTempWStr; |
1110 | } |
1111 | else |
1112 | { |
1113 | ERROR( "InternalMalloc failed.\n" ); |
1114 | LOGEXIT("vfwprintf returns int -1\n" ); |
1115 | PERF_EXIT(vfwprintf); |
1116 | va_end(ap); |
1117 | return -1; |
1118 | } |
1119 | } |
1120 | else |
1121 | { |
1122 | ASSERT( "Unable to convert from multibyte " |
1123 | " to wide char.\n" ); |
1124 | LOGEXIT("vfwprintf returns int -1\n" ); |
1125 | PERF_EXIT(vfwprintf); |
1126 | va_end(ap); |
1127 | return -1; |
1128 | } |
1129 | } |
1130 | } |
1131 | |
1132 | if (TempWStr == NULL) |
1133 | { |
1134 | TempWStr = __wnullstring; |
1135 | } |
1136 | |
1137 | INT Length = PAL_wcslen(TempWStr); |
1138 | WorkingWStr = (LPWSTR) InternalMalloc((sizeof(WCHAR) * (Length + 1))); |
1139 | if (!WorkingWStr) |
1140 | { |
1141 | ERROR("InternalMalloc failed\n" ); |
1142 | LOGEXIT("vfwprintf returns int -1\n" ); |
1143 | PERF_EXIT(vfwprintf); |
1144 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
1145 | free(AllocedTempWStr); |
1146 | va_end(ap); |
1147 | return -1; |
1148 | } |
1149 | if (PRECISION_DOT == Precision) |
1150 | { |
1151 | /* copy nothing */ |
1152 | *WorkingWStr = 0; |
1153 | Length = 0; |
1154 | } |
1155 | else if (Precision > 0 && Precision < Length) |
1156 | { |
1157 | if (wcsncpy_s(WorkingWStr, (Length + 1), TempWStr, Precision+1) != SAFECRT_SUCCESS) |
1158 | { |
1159 | ERROR("Internal_AddPaddingVfwprintf failed\n" ); |
1160 | free(AllocedTempWStr); |
1161 | free(WorkingWStr); |
1162 | LOGEXIT("wcsncpy_s failed!\n" ); |
1163 | PERF_EXIT(vfwprintf); |
1164 | va_end(ap); |
1165 | return (-1); |
1166 | } |
1167 | |
1168 | Length = Precision; |
1169 | } |
1170 | /* copy everything */ |
1171 | else |
1172 | { |
1173 | PAL_wcscpy(WorkingWStr, TempWStr); |
1174 | } |
1175 | |
1176 | |
1177 | /* do the padding (if needed)*/ |
1178 | paddingReturnValue = |
1179 | Internal_AddPaddingVfwprintf( pthrCurrent, stream, WorkingWStr, |
1180 | Width - Length, |
1181 | Flags,textMode); |
1182 | |
1183 | if (paddingReturnValue == -1) |
1184 | { |
1185 | ERROR("Internal_AddPaddingVfwprintf failed\n" ); |
1186 | free(AllocedTempWStr); |
1187 | free(WorkingWStr); |
1188 | LOGEXIT("vfwprintf returns int -1\n" ); |
1189 | PERF_EXIT(vfwprintf); |
1190 | va_end(ap); |
1191 | return (-1); |
1192 | } |
1193 | written += paddingReturnValue; |
1194 | |
1195 | free(WorkingWStr); |
1196 | free(AllocedTempWStr); |
1197 | } |
1198 | else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR) |
1199 | { |
1200 | if (WIDTH_STAR == Width || |
1201 | WIDTH_INVALID == Width) |
1202 | { |
1203 | /* ignore (because it's a char), and remove arg */ |
1204 | TempInt = va_arg(ap, INT); /* value not used */ |
1205 | } |
1206 | |
1207 | if (PRECISION_STAR == Precision || |
1208 | PRECISION_INVALID == Precision) |
1209 | { |
1210 | /* ignore (because it's a char), and remove arg */ |
1211 | TempInt = va_arg(ap, INT); /* value not used */ |
1212 | } |
1213 | |
1214 | TempWChar[0] = va_arg(ap, int); |
1215 | TempWChar[1] = 0; |
1216 | |
1217 | /* do the padding (if needed)*/ |
1218 | paddingReturnValue = |
1219 | Internal_AddPaddingVfwprintf(pthrCurrent, stream, TempWChar, |
1220 | Width - 1, |
1221 | Flags,textMode); |
1222 | if (paddingReturnValue == -1) |
1223 | { |
1224 | ERROR("Internal_AddPaddingVfwprintf failed\n" ); |
1225 | LOGEXIT("vfwprintf returns int -1\n" ); |
1226 | PERF_EXIT(vfwprintf); |
1227 | va_end(ap); |
1228 | return(-1); |
1229 | } |
1230 | written += paddingReturnValue; |
1231 | } |
1232 | /* this places the number of bytes written to the buffer in the |
1233 | next arg */ |
1234 | else if (Type == PFF_TYPE_N) |
1235 | { |
1236 | if (WIDTH_STAR == Width) |
1237 | { |
1238 | Width = va_arg(ap, INT); |
1239 | } |
1240 | |
1241 | if (PRECISION_STAR == Precision) |
1242 | { |
1243 | Precision = va_arg(ap, INT); |
1244 | } |
1245 | |
1246 | if (Prefix == PFF_PREFIX_SHORT) |
1247 | { |
1248 | *(va_arg(ap, short *)) = written; |
1249 | } |
1250 | else |
1251 | { |
1252 | *(va_arg(ap, LPLONG)) = written; |
1253 | } |
1254 | } |
1255 | else |
1256 | { |
1257 | // Types that sprintf can handle. |
1258 | |
1259 | /* note: I'm using the wide buffer as a (char *) buffer when I |
1260 | pass it to sprintf(). After I get the buffer back I make a |
1261 | backup of the chars copied and then convert them to wide |
1262 | and place them in the buffer (BufferPtr) */ |
1263 | |
1264 | // This argument will be limited to 1024 characters. |
1265 | // It should be enough. |
1266 | size_t TEMP_COUNT = 1024; |
1267 | char TempSprintfStrBuffer[1024]; |
1268 | char *TempSprintfStrPtr = NULL; |
1269 | char *TempSprintfStr = TempSprintfStrBuffer; |
1270 | LPWSTR TempWideBuffer; |
1271 | |
1272 | TempInt = 0; |
1273 | // %h (short) doesn't seem to be handled properly by local sprintf, |
1274 | // so we do the truncation ourselves for some cases. |
1275 | if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT) |
1276 | { |
1277 | // Convert from pointer -> int -> short to avoid warnings. |
1278 | long trunc1; |
1279 | short trunc2; |
1280 | |
1281 | trunc1 = va_arg(ap, LONG); |
1282 | trunc2 = (short)trunc1; |
1283 | trunc1 = trunc2; |
1284 | |
1285 | TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, trunc1); |
1286 | |
1287 | if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT) |
1288 | { |
1289 | if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt))) |
1290 | { |
1291 | ERROR("InternalMalloc failed\n" ); |
1292 | LOGEXIT("vfwprintf returns int -1\n" ); |
1293 | PERF_EXIT(vfwprintf); |
1294 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
1295 | va_end(ap); |
1296 | return -1; |
1297 | } |
1298 | |
1299 | TempSprintfStr = TempSprintfStrPtr; |
1300 | snprintf(TempSprintfStr, TempInt, TempBuff, trunc2); |
1301 | } |
1302 | } |
1303 | else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT) |
1304 | { |
1305 | // Convert explicitly from int to short to get |
1306 | // correct sign extension for shorts on all systems. |
1307 | int n; |
1308 | short s; |
1309 | |
1310 | n = va_arg(ap, int); |
1311 | s = (short) n; |
1312 | |
1313 | TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, s); |
1314 | |
1315 | if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT) |
1316 | { |
1317 | if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt))) |
1318 | { |
1319 | ERROR("InternalMalloc failed\n" ); |
1320 | LOGEXIT("vfwprintf returns int -1\n" ); |
1321 | PERF_EXIT(vfwprintf); |
1322 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
1323 | va_end(ap); |
1324 | return -1; |
1325 | } |
1326 | |
1327 | TempSprintfStr = TempSprintfStrPtr; |
1328 | snprintf(TempSprintfStr, TempInt, TempBuff, s); |
1329 | } |
1330 | } |
1331 | else |
1332 | { |
1333 | va_list apcopy; |
1334 | |
1335 | va_copy(apcopy, ap); |
1336 | TempInt = _vsnprintf_s(TempSprintfStr, TEMP_COUNT, _TRUNCATE, TempBuff, apcopy); |
1337 | va_end(apcopy); |
1338 | PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); |
1339 | |
1340 | if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT) |
1341 | { |
1342 | if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt))) |
1343 | { |
1344 | ERROR("InternalMalloc failed\n" ); |
1345 | LOGEXIT("vfwprintf returns int -1\n" ); |
1346 | PERF_EXIT(vfwprintf); |
1347 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
1348 | va_end(ap); |
1349 | return -1; |
1350 | } |
1351 | |
1352 | TempSprintfStr = TempSprintfStrPtr; |
1353 | va_copy(apcopy, ap); |
1354 | _vsnprintf_s(TempSprintfStr, TempInt, _TRUNCATE, TempBuff, apcopy); |
1355 | va_end(apcopy); |
1356 | PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); |
1357 | } |
1358 | } |
1359 | |
1360 | mbtowcResult = MultiByteToWideChar(CP_ACP, 0, |
1361 | TempSprintfStr, -1, |
1362 | NULL, 0); |
1363 | |
1364 | if (mbtowcResult == 0) |
1365 | { |
1366 | ERROR("MultiByteToWideChar failed\n" ); |
1367 | if(TempSprintfStrPtr) |
1368 | { |
1369 | free(TempSprintfStrPtr); |
1370 | } |
1371 | LOGEXIT("vfwprintf returns int -1\n" ); |
1372 | PERF_EXIT(vfwprintf); |
1373 | va_end(ap); |
1374 | return -1; |
1375 | } |
1376 | |
1377 | TempWideBuffer = (LPWSTR) InternalMalloc(mbtowcResult*sizeof(WCHAR)); |
1378 | if (!TempWideBuffer) |
1379 | { |
1380 | ERROR("InternalMalloc failed\n" ); |
1381 | LOGEXIT("vfwprintf returns int -1\n" ); |
1382 | PERF_EXIT(vfwprintf); |
1383 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
1384 | if(TempSprintfStrPtr) |
1385 | { |
1386 | free(TempSprintfStrPtr); |
1387 | } |
1388 | va_end(ap); |
1389 | return -1; |
1390 | } |
1391 | |
1392 | MultiByteToWideChar(CP_ACP, 0, TempSprintfStr, -1, |
1393 | TempWideBuffer, mbtowcResult); |
1394 | |
1395 | ret = Internal_Convertfwrite( |
1396 | pthrCurrent, |
1397 | TempWideBuffer, |
1398 | sizeof(wchar_16), |
1399 | mbtowcResult-1, |
1400 | (FILE*)stream->bsdFilePtr, |
1401 | textMode); |
1402 | |
1403 | if (-1 == ret) |
1404 | { |
1405 | ERROR("fwrite() failed with errno == %d (%s)\n" , errno, strerror(errno)); |
1406 | LOGEXIT("vfwprintf returns int -1\n" ); |
1407 | PERF_EXIT(vfwprintf); |
1408 | free(TempWideBuffer); |
1409 | if(TempSprintfStrPtr) |
1410 | { |
1411 | free(TempSprintfStrPtr); |
1412 | } |
1413 | va_end(ap); |
1414 | return -1; |
1415 | } |
1416 | if(TempSprintfStrPtr) |
1417 | { |
1418 | free(TempSprintfStrPtr); |
1419 | } |
1420 | free(TempWideBuffer); |
1421 | } |
1422 | } |
1423 | else |
1424 | { |
1425 | ret = Internal_Convertfwrite( |
1426 | pthrCurrent, |
1427 | Fmt++, |
1428 | sizeof(wchar_16), |
1429 | 1, |
1430 | (FILE*)stream->bsdFilePtr, |
1431 | textMode); /* copy regular chars into buffer */ |
1432 | |
1433 | if (-1 == ret) |
1434 | { |
1435 | ERROR("fwrite() failed with errno == %d\n" , errno); |
1436 | LOGEXIT("vfwprintf returns int -1\n" ); |
1437 | PERF_EXIT(vfwprintf); |
1438 | va_end(ap); |
1439 | return -1; |
1440 | } |
1441 | ++written; |
1442 | } |
1443 | } |
1444 | |
1445 | LOGEXIT("vfwprintf returns int %d\n" , written); |
1446 | PERF_EXIT(vfwprintf); |
1447 | va_end(ap); |
1448 | return (written); |
1449 | } |
1450 | |
1451 | int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list aparg) |
1452 | { |
1453 | CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */ |
1454 | LPCSTR Fmt = format; |
1455 | LPCWSTR TempWStr; |
1456 | LPSTR TempStr; |
1457 | WCHAR TempWChar; |
1458 | INT Flags; |
1459 | INT Width; |
1460 | INT Precision; |
1461 | INT Prefix; |
1462 | INT Type; |
1463 | INT Length; |
1464 | INT TempInt; |
1465 | int wctombResult; |
1466 | int written = 0; |
1467 | int paddingReturnValue; |
1468 | va_list ap; |
1469 | |
1470 | PERF_ENTRY(vfprintf); |
1471 | |
1472 | va_copy(ap, aparg); |
1473 | |
1474 | while (*Fmt) |
1475 | { |
1476 | if (*Fmt == '%' && |
1477 | TRUE == Internal_ExtractFormatA(pthrCurrent, &Fmt, TempBuff, &Flags, |
1478 | &Width, &Precision, |
1479 | &Prefix, &Type)) |
1480 | { |
1481 | if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING) |
1482 | { |
1483 | if (WIDTH_STAR == Width) |
1484 | { |
1485 | Width = va_arg(ap, INT); |
1486 | } |
1487 | else if (WIDTH_INVALID == Width) |
1488 | { |
1489 | /* both a '*' and a number, ignore, but remove arg */ |
1490 | TempInt = va_arg(ap, INT); /* value not used */ |
1491 | } |
1492 | |
1493 | if (PRECISION_STAR == Precision) |
1494 | { |
1495 | Precision = va_arg(ap, INT); |
1496 | } |
1497 | else if (PRECISION_INVALID == Precision) |
1498 | { |
1499 | /* both a '*' and a number, ignore, but remove arg */ |
1500 | TempInt = va_arg(ap, INT); /* value not used */ |
1501 | } |
1502 | |
1503 | TempWStr = va_arg(ap, LPWSTR); |
1504 | if (TempWStr == NULL)\ |
1505 | { |
1506 | TempWStr = __wnullstring; |
1507 | } |
1508 | Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, 0, |
1509 | 0, 0, 0); |
1510 | if (!Length) |
1511 | { |
1512 | ASSERT("WideCharToMultiByte failed. Error is %d\n" , |
1513 | GetLastError()); |
1514 | PERF_EXIT(vfprintf); |
1515 | va_end(ap); |
1516 | return -1; |
1517 | } |
1518 | TempStr = (LPSTR) InternalMalloc(Length); |
1519 | if (!TempStr) |
1520 | { |
1521 | ERROR("InternalMalloc failed\n" ); |
1522 | pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
1523 | PERF_EXIT(vfprintf); |
1524 | va_end(ap); |
1525 | return -1; |
1526 | } |
1527 | if (PRECISION_DOT == Precision) |
1528 | { |
1529 | /* copy nothing */ |
1530 | *TempStr = 0; |
1531 | Length = 0; |
1532 | } |
1533 | else if (Precision > 0 && Precision < Length - 1) |
1534 | { |
1535 | Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, |
1536 | Precision, TempStr, Length, |
1537 | 0, 0); |
1538 | if (!Length) |
1539 | { |
1540 | ASSERT("WideCharToMultiByte failed. Error is %d\n" , |
1541 | GetLastError()); |
1542 | free(TempStr); |
1543 | PERF_EXIT(vfprintf); |
1544 | va_end(ap); |
1545 | return -1; |
1546 | } |
1547 | TempStr[Length] = 0; |
1548 | Length = Precision; |
1549 | } |
1550 | /* copy everything */ |
1551 | else |
1552 | { |
1553 | wctombResult = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, |
1554 | TempStr, Length, 0, 0); |
1555 | if (!wctombResult) |
1556 | { |
1557 | ASSERT("WideCharToMultiByte failed. Error is %d\n" , |
1558 | GetLastError()); |
1559 | free(TempStr); |
1560 | PERF_EXIT(vfprintf); |
1561 | va_end(ap); |
1562 | return -1; |
1563 | } |
1564 | --Length; /* exclude null char */ |
1565 | } |
1566 | |
1567 | /* do the padding (if needed)*/ |
1568 | paddingReturnValue = |
1569 | Internal_AddPaddingVfprintf(pthrCurrent, stream, TempStr, |
1570 | Width - Length, Flags); |
1571 | if (-1 == paddingReturnValue) |
1572 | { |
1573 | ERROR("Internal_AddPaddingVfprintf failed\n" ); |
1574 | free(TempStr); |
1575 | PERF_EXIT(vfprintf); |
1576 | va_end(ap); |
1577 | return -1; |
1578 | } |
1579 | written += paddingReturnValue; |
1580 | |
1581 | free(TempStr); |
1582 | } |
1583 | else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR) |
1584 | { |
1585 | CHAR TempBuffer[5]; |
1586 | if (WIDTH_STAR == Width || |
1587 | WIDTH_INVALID == Width) |
1588 | { |
1589 | /* ignore (because it's a char), and remove arg */ |
1590 | TempInt = va_arg(ap, INT); /* value not used */ |
1591 | } |
1592 | if (PRECISION_STAR == Precision || |
1593 | PRECISION_INVALID == Precision) |
1594 | { |
1595 | /* ignore (because it's a char), and remove arg */ |
1596 | TempInt = va_arg(ap, INT); /* value not used */ |
1597 | } |
1598 | |
1599 | TempWChar = va_arg(ap, int); |
1600 | Length = WideCharToMultiByte(CP_ACP, 0, &TempWChar, 1, |
1601 | TempBuffer, sizeof(TempBuffer), |
1602 | 0, 0); |
1603 | if (!Length) |
1604 | { |
1605 | ASSERT("WideCharToMultiByte failed. Error is %d\n" , |
1606 | GetLastError()); |
1607 | PERF_EXIT(vfprintf); |
1608 | va_end(ap); |
1609 | return -1; |
1610 | } |
1611 | TempBuffer[Length] = 0; |
1612 | |
1613 | /* do the padding (if needed)*/ |
1614 | paddingReturnValue = |
1615 | Internal_AddPaddingVfprintf(pthrCurrent, stream, TempBuffer, |
1616 | Width - Length, Flags); |
1617 | if (-1 == paddingReturnValue) |
1618 | { |
1619 | ERROR("Internal_AddPaddingVfprintf failed\n" ); |
1620 | PERF_EXIT(vfprintf); |
1621 | va_end(ap); |
1622 | return -1; |
1623 | } |
1624 | written += paddingReturnValue; |
1625 | |
1626 | } |
1627 | /* this places the number of bytes written to the buffer in the |
1628 | next arg */ |
1629 | else if (Type == PFF_TYPE_N) |
1630 | { |
1631 | if (WIDTH_STAR == Width) |
1632 | { |
1633 | Width = va_arg(ap, INT); |
1634 | } |
1635 | if (PRECISION_STAR == Precision) |
1636 | { |
1637 | Precision = va_arg(ap, INT); |
1638 | } |
1639 | |
1640 | if (Prefix == PFF_PREFIX_SHORT) |
1641 | { |
1642 | *(va_arg(ap, short *)) = written; |
1643 | } |
1644 | else |
1645 | { |
1646 | *(va_arg(ap, LPLONG)) = written; |
1647 | } |
1648 | } |
1649 | else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0) |
1650 | { |
1651 | // Some versions of fprintf don't support 0-padded chars, |
1652 | // so we handle them here. |
1653 | char ch[2]; |
1654 | |
1655 | ch[0] = (char) va_arg(ap, int); |
1656 | ch[1] = '\0'; |
1657 | Length = 1; |
1658 | paddingReturnValue = Internal_AddPaddingVfprintf( |
1659 | pthrCurrent, |
1660 | stream, |
1661 | ch, |
1662 | Width - Length, |
1663 | Flags); |
1664 | if (-1 == paddingReturnValue) |
1665 | { |
1666 | ERROR("Internal_AddPaddingVfprintf failed\n" ); |
1667 | PERF_EXIT(vfprintf); |
1668 | va_end(ap); |
1669 | return -1; |
1670 | } |
1671 | written += paddingReturnValue; |
1672 | } |
1673 | else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0) |
1674 | { |
1675 | // Some versions of fprintf don't support 0-padded strings, |
1676 | // so we handle them here. |
1677 | const char *tempStr; |
1678 | |
1679 | tempStr = va_arg(ap, char *); |
1680 | if (tempStr == NULL) |
1681 | { |
1682 | tempStr = __nullstring; |
1683 | } |
1684 | Length = strlen(tempStr); |
1685 | paddingReturnValue = Internal_AddPaddingVfprintf( |
1686 | pthrCurrent, |
1687 | stream, |
1688 | tempStr, |
1689 | Width - Length, |
1690 | Flags); |
1691 | if (-1 == paddingReturnValue) |
1692 | { |
1693 | ERROR("Internal_AddPaddingVfprintf failed\n" ); |
1694 | PERF_EXIT(vfprintf); |
1695 | va_end(ap); |
1696 | return -1; |
1697 | } |
1698 | written += paddingReturnValue; |
1699 | } |
1700 | else |
1701 | { |
1702 | // Types that fprintf can handle. |
1703 | TempInt = 0; |
1704 | |
1705 | // %h (short) doesn't seem to be handled properly by local sprintf, |
1706 | // so we do the truncation ourselves for some cases. |
1707 | if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT) |
1708 | { |
1709 | // Convert from pointer -> int -> short to avoid warnings. |
1710 | long trunc1; |
1711 | short trunc2; |
1712 | |
1713 | trunc1 = va_arg(ap, LONG); |
1714 | trunc2 = (short)trunc1; |
1715 | trunc1 = trunc2; |
1716 | |
1717 | TempInt = fprintf(stream->bsdFilePtr, TempBuff, trunc1); |
1718 | } |
1719 | else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT) |
1720 | { |
1721 | // Convert explicitly from int to short to get |
1722 | // correct sign extension for shorts on all systems. |
1723 | int n; |
1724 | short s; |
1725 | |
1726 | n = va_arg(ap, int); |
1727 | s = (short) n; |
1728 | |
1729 | TempInt = fprintf( stream->bsdFilePtr, TempBuff, s); |
1730 | } |
1731 | else |
1732 | { |
1733 | va_list apcopy; |
1734 | va_copy(apcopy, ap); |
1735 | TempInt = vfprintf(stream->bsdFilePtr, TempBuff, apcopy); |
1736 | va_end(apcopy); |
1737 | PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); |
1738 | } |
1739 | |
1740 | if (-1 == TempInt) |
1741 | { |
1742 | ERROR("vfprintf returned an error\n" ); |
1743 | } |
1744 | else |
1745 | { |
1746 | written += TempInt; |
1747 | } |
1748 | } |
1749 | } |
1750 | else |
1751 | { |
1752 | |
1753 | #if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL |
1754 | clearerr (stream->bsdFilePtr); |
1755 | #endif |
1756 | |
1757 | InternalFwrite(Fmt++, 1, 1, stream->bsdFilePtr, &stream->PALferrorCode); /* copy regular chars into buffer */ |
1758 | if (stream->PALferrorCode == PAL_FILE_ERROR) |
1759 | { |
1760 | ERROR("fwrite() failed with errno == %d\n" , errno); |
1761 | PERF_EXIT(vfprintf); |
1762 | va_end(ap); |
1763 | return -1; |
1764 | } |
1765 | ++written; |
1766 | } |
1767 | } |
1768 | |
1769 | va_end(ap); |
1770 | |
1771 | PERF_EXIT(vfprintf); |
1772 | return written; |
1773 | } |
1774 | |