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
9Module Name:
10
11 printfcpp.cpp
12
13Abstract:
14
15 Implementation of suspension safe printf functions.
16
17Revision 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
34SET_DEFAULT_DEBUG_CHANNEL(CRT);
35
36using namespace CorUnix;
37
38static const char __nullstring[] = "(null)"; /* string to print on null ptr */
39static const WCHAR __wnullstring[] = W("(null)"); /* string to print on null ptr */
40
41int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap);
42int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list ap);
43
44extern "C"
45{
46
47/*******************************************************************************
48Function:
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
54static 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/*******************************************************************************
110Function:
111 Internal_ExtractFormatA
112
113Paramaters:
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
134Notes:
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*******************************************************************************/
150BOOL Internal_ExtractFormatA(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/*******************************************************************************
450Function:
451 Internal_ExtractFormatW
452
453 -- see Internal_ExtractFormatA above
454*******************************************************************************/
455BOOL Internal_ExtractFormatW(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/*******************************************************************************
778Function:
779 Internal_AddPaddingVfprintf
780
781Parameters:
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
792INT 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
873Done:
874 free(OutOriginal);
875
876 return Written;
877}
878
879/*******************************************************************************
880Function:
881 Internal_AddPaddingVfwprintf
882
883Parameters:
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*******************************************************************************/
893static 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/*******************************************************************************
979Function:
980 PAL_vfprintf
981
982Parameters:
983 stream
984 - out stream
985 Format
986 - format string
987 ap
988 - stdarg parameter list
989*******************************************************************************/
990
991int __cdecl PAL_vfprintf(PAL_FILE *stream, const char *format, va_list ap)
992{
993 return CoreVfprintf(InternalGetCurrentThread(), stream, format, ap);
994}
995
996/*******************************************************************************
997Function:
998 PAL_vfwprintf
999
1000Parameters:
1001 stream
1002 - out stream
1003 Format
1004 - format string
1005 ap
1006 - stdarg parameter list
1007*******************************************************************************/
1008
1009int __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
1016int CorUnix::InternalVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap)
1017{
1018 return CoreVfprintf(pthrCurrent, stream, format, ap);
1019}
1020
1021int 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
1451int 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