| // |
| // Copyright (c) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
| // |
| |
| /*++ |
| |
| |
| |
| Module Name: |
| |
| printfcpp.cpp |
| |
| Abstract: |
| |
| Implementation of suspension safe printf functions. |
| |
| Revision History: |
| |
| |
| |
| --*/ |
| |
| #include "pal/corunix.hpp" |
| #include "pal/thread.hpp" |
| #include "pal/malloc.hpp" |
| #include "pal/file.hpp" |
| #include "pal/printfcpp.hpp" |
| #include "pal/palinternal.h" |
| #include "pal/dbgmsg.h" |
| #include "pal/cruntime.h" |
| |
| #include <errno.h> |
| |
| SET_DEFAULT_DEBUG_CHANNEL(CRT); |
| |
| using namespace CorUnix; |
| |
| int CoreWvsnprintf(CPalThread *pthrCurrent, LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list ap); |
| int CoreVsnprintf(CPalThread *pthrCurrent, LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap); |
| int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap); |
| int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char16_t *format, va_list ap); |
| |
| extern "C" |
| { |
| |
| /******************************************************************************* |
| Function: |
| Internal_Convertfwrite |
| This function is a wrapper around fwrite for cases where the buffer has |
| to be converted from WideChar to MultiByte |
| *******************************************************************************/ |
| |
| static int Internal_Convertfwrite(CPalThread *pthrCurrent, const void *buffer, size_t size, size_t count, FILE *stream, BOOL convert) |
| { |
| int ret; |
| int iError = 0; |
| |
| #if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL |
| clearerr (stream); |
| #endif |
| |
| if(convert) |
| { |
| int nsize; |
| LPSTR newBuff = 0; |
| nsize = WideCharToMultiByte(CP_ACP, 0,(LPCWSTR)buffer, count, 0, 0, 0, 0); |
| if (!nsize) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", GetLastError()); |
| return -1; |
| } |
| newBuff = (LPSTR) InternalMalloc(nsize); |
| if (!newBuff) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| return -1; |
| } |
| nsize = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)buffer, count, newBuff, nsize, 0, 0); |
| if (!nsize) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", GetLastError()); |
| InternalFree(newBuff); |
| return -1; |
| } |
| ret = InternalFwrite(newBuff, 1, nsize, stream, &iError); |
| if (iError != 0) |
| { |
| ERROR("InternalFwrite did not write the whole buffer. Error is %d\n", iError); |
| InternalFree(newBuff); |
| return -1; |
| } |
| InternalFree(newBuff); |
| } |
| else |
| { |
| ret = InternalFwrite(buffer, size, count, stream, &iError); |
| if (iError != 0) |
| { |
| ERROR("InternalFwrite did not write the whole buffer. Error is %d\n", iError); |
| return -1; |
| } |
| } |
| return ret; |
| |
| } |
| |
| /******************************************************************************* |
| Function: |
| Internal_ExtractFormatA |
| |
| Paramaters: |
| Fmt |
| - format string to parse |
| - first character must be a '%' |
| - paramater gets updated to point to the character after |
| the %<foo> format string |
| Out |
| - buffer will contain the %<foo> format string |
| Flags |
| - paramater will be set with the PRINTF_FORMAT_FLAGS defined above |
| Width |
| - will contain the width specified by the format string |
| - -1 if none given |
| Precision |
| - will contain the precision specified in the format string |
| - -1 if none given |
| Prefix |
| - an enumeration of the type prefix |
| Type |
| - an enumeration of the type value |
| |
| Notes: |
| - I'm also handling the undocumented %ws, %wc, %w... |
| - %#10x, when we have a width greater than the length (i.e padding) the |
| length of the padding is not consistent with MS's wsprintf |
| (MS adds an extra 2 padding chars, length of "0x") |
| - MS's wsprintf seems to ingore a 'h' prefix for number types |
| - MS's "%p" is different than gcc's |
| e.g. printf("%p", NULL); |
| MS --> 00000000 |
| gcc --> 0x0 |
| - the length of the exponent (precision) for floating types is different |
| between MS and gcc |
| e.g. printf("%E", 256.0); |
| MS --> 2.560000E+002 |
| gcc --> 2.560000E+02 |
| *******************************************************************************/ |
| BOOL Internal_ExtractFormatA(CPalThread *pthrCurrent, LPCSTR *Fmt, LPSTR Out, LPINT Flags, |
| LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type) |
| { |
| BOOL Result = FALSE; |
| LPSTR TempStr; |
| LPSTR TempStrPtr; |
| |
| *Width = WIDTH_DEFAULT; |
| *Precision = PRECISION_DEFAULT; |
| *Flags = PFF_NONE; |
| *Prefix = PFF_PREFIX_DEFAULT; |
| *Type = PFF_TYPE_DEFAULT; |
| |
| if (*Fmt && **Fmt == '%') |
| { |
| *Out++ = *(*Fmt)++; |
| } |
| else |
| { |
| return Result; |
| } |
| |
| /* we'll never need a temp string longer than the original */ |
| TempStrPtr = TempStr = (LPSTR) InternalMalloc(strlen(*Fmt)+1); |
| if (!TempStr) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| return Result; |
| } |
| |
| /* parse flags */ |
| while (**Fmt && (**Fmt == '-' || **Fmt == '+' || |
| **Fmt == '0' || **Fmt == ' ' || **Fmt == '#')) |
| { |
| switch (**Fmt) |
| { |
| case '-': |
| *Flags |= PFF_MINUS; break; |
| case '+': |
| *Flags |= PFF_PLUS; break; |
| case '0': |
| *Flags |= PFF_ZERO; break; |
| case ' ': |
| *Flags |= PFF_SPACE; break; |
| case '#': |
| *Flags |= PFF_POUND; break; |
| } |
| *Out++ = *(*Fmt)++; |
| } |
| /* '-' flag negates '0' flag */ |
| if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO)) |
| { |
| *Flags -= PFF_ZERO; |
| } |
| |
| /* grab width specifier */ |
| if (isdigit((unsigned char) **Fmt)) |
| { |
| TempStrPtr = TempStr; |
| while (isdigit((unsigned char) **Fmt)) |
| { |
| *TempStrPtr++ = **Fmt; |
| *Out++ = *(*Fmt)++; |
| } |
| *TempStrPtr = 0; /* end string */ |
| *Width = atoi(TempStr); |
| if (*Width < 0) |
| { |
| ERROR("atoi returned a negative value indicative of an overflow.\n"); |
| pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); |
| return Result; |
| } |
| } |
| else if (**Fmt == '*') |
| { |
| *Width = WIDTH_STAR; |
| *Out++ = *(*Fmt)++; |
| if (isdigit((unsigned char) **Fmt)) |
| { |
| /* this is an invalid width because we have a * then a number */ |
| /* printf handles this by just printing the whole string */ |
| *Width = WIDTH_INVALID; |
| while (isdigit((unsigned char) **Fmt)) |
| { |
| *Out++ = *(*Fmt)++; |
| } |
| } |
| } |
| |
| |
| /* grab precision specifier */ |
| if (**Fmt == '.') |
| { |
| *Out++ = *(*Fmt)++; |
| if (isdigit((unsigned char) **Fmt)) |
| { |
| TempStrPtr = TempStr; |
| while (isdigit((unsigned char) **Fmt)) |
| { |
| *TempStrPtr++ = **Fmt; |
| *Out++ = *(*Fmt)++; |
| } |
| *TempStrPtr = 0; /* end string */ |
| *Precision = atoi(TempStr); |
| if (*Precision < 0) |
| { |
| ERROR("atoi returned a negative value indicative of an overflow.\n"); |
| pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); |
| return Result; |
| } |
| } |
| else if (**Fmt == '*') |
| { |
| *Precision = PRECISION_STAR; |
| *Out++ = *(*Fmt)++; |
| if (isdigit((unsigned char) **Fmt)) |
| { |
| /* this is an invalid precision because we have a .* then a number */ |
| /* printf handles this by just printing the whole string */ |
| *Precision = PRECISION_INVALID; |
| while (isdigit((unsigned char) **Fmt)) |
| { |
| *Out++ = *(*Fmt)++; |
| } |
| } |
| } |
| else |
| { |
| *Precision = PRECISION_DOT; |
| } |
| } |
| |
| #ifdef BIT64 |
| if (**Fmt == 'p') |
| { |
| *Prefix = PFF_PREFIX_LONGLONG; |
| } |
| #endif |
| if ((*Fmt)[0] == 'I') |
| { |
| /* grab prefix of 'I64' for __int64 */ |
| if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4') |
| { |
| /* convert to 'll' so that Unix snprintf can handle it */ |
| *Fmt += 3; |
| *Prefix = PFF_PREFIX_LONGLONG; |
| } |
| /* grab prefix of 'I32' for __int32 */ |
| else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2') |
| { |
| *Fmt += 3; |
| } |
| else |
| { |
| ++(*Fmt); |
| #ifdef BIT64 |
| /* convert to 'll' so that Unix snprintf can handle it */ |
| *Prefix = PFF_PREFIX_LONGLONG; |
| #endif |
| } |
| } |
| /* grab a prefix of 'h' */ |
| else if (**Fmt == 'h') |
| { |
| *Prefix = PFF_PREFIX_SHORT; |
| ++(*Fmt); |
| } |
| /* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */ |
| else if (**Fmt == 'l' || **Fmt == 'w') |
| { |
| ++(*Fmt); |
| #ifdef BIT64 |
| // Only want to change the prefix on 64 bit when printing characters. |
| if (**Fmt == 'c' || **Fmt == 's') |
| #endif |
| { |
| *Prefix = PFF_PREFIX_LONG; |
| } |
| if (**Fmt == 'l') |
| { |
| *Prefix = PFF_PREFIX_LONGLONG; |
| ++(*Fmt); |
| } |
| } |
| else if (**Fmt == 'L') |
| { |
| /* a prefix of 'L' seems to be ignored */ |
| ++(*Fmt); |
| } |
| |
| /* grab type 'c' */ |
| if (**Fmt == 'c' || **Fmt == 'C') |
| { |
| *Type = PFF_TYPE_CHAR; |
| if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'C') |
| { |
| *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ |
| } |
| if (*Prefix == PFF_PREFIX_LONG) |
| { |
| *Out++ = 'l'; |
| } |
| *Out++ = 'c'; |
| ++(*Fmt); |
| Result = TRUE; |
| } |
| /* grab type 's' */ |
| else if (**Fmt == 's' || **Fmt == 'S') |
| { |
| *Type = PFF_TYPE_STRING; |
| if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'S') |
| { |
| *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ |
| } |
| if (*Prefix == PFF_PREFIX_LONG) |
| { |
| *Out++ = 'l'; |
| } |
| *Out++ = 's'; |
| ++(*Fmt); |
| Result = TRUE; |
| } |
| /* grab int types */ |
| else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' || |
| **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X') |
| { |
| *Type = PFF_TYPE_INT; |
| if (*Prefix == PFF_PREFIX_SHORT) |
| { |
| *Out++ = 'h'; |
| } |
| else if (*Prefix == PFF_PREFIX_LONG) |
| { |
| *Out++ = 'l'; |
| } |
| else if (*Prefix == PFF_PREFIX_LONGLONG) |
| { |
| *Out++ = 'l'; |
| *Out++ = 'l'; |
| } |
| *Out++ = *(*Fmt)++; |
| Result = TRUE; |
| } |
| else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' || |
| **Fmt == 'g' || **Fmt == 'G') |
| { |
| /* we can safely ignore the prefixes and only add the type*/ |
| *Type = PFF_TYPE_FLOAT; |
| *Out++ = *(*Fmt)++; |
| Result = TRUE; |
| } |
| else if (**Fmt == 'n') |
| { |
| if (*Prefix == PFF_PREFIX_SHORT) |
| { |
| *Out++ = 'h'; |
| } |
| *Out++ = *(*Fmt)++; |
| *Type = PFF_TYPE_N; |
| Result = TRUE; |
| } |
| else if (**Fmt == 'p') |
| { |
| *Type = PFF_TYPE_P; |
| (*Fmt)++; |
| |
| if (*Prefix == PFF_PREFIX_LONGLONG) |
| { |
| if (*Precision == PRECISION_DEFAULT) |
| { |
| *Precision = 16; |
| *Out++ = '.'; |
| *Out++ = '1'; |
| *Out++ = '6'; |
| } |
| /* native *printf does not support %I64p |
| (actually %llp), so we need to cheat a little bit */ |
| *Out++ = 'l'; |
| *Out++ = 'l'; |
| } |
| else |
| { |
| if (*Precision == PRECISION_DEFAULT) |
| { |
| *Precision = 8; |
| *Out++ = '.'; |
| *Out++ = '8'; |
| } |
| } |
| *Out++ = 'X'; |
| Result = TRUE; |
| } |
| |
| *Out = 0; /* end the string */ |
| InternalFree(TempStr); |
| return Result; |
| } |
| |
| /******************************************************************************* |
| Function: |
| Internal_ExtractFormatW |
| |
| -- see Internal_ExtractFormatA above |
| *******************************************************************************/ |
| BOOL Internal_ExtractFormatW(CPalThread *pthrCurrent, LPCWSTR *Fmt, LPSTR Out, LPINT Flags, |
| LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type) |
| { |
| BOOL Result = FALSE; |
| LPSTR TempStr; |
| LPSTR TempStrPtr; |
| |
| *Width = WIDTH_DEFAULT; |
| *Precision = PRECISION_DEFAULT; |
| *Flags = PFF_NONE; |
| *Prefix = PFF_PREFIX_DEFAULT; |
| *Type = PFF_TYPE_DEFAULT; |
| |
| if (*Fmt && **Fmt == '%') |
| { |
| *Out++ = (CHAR) *(*Fmt)++; |
| } |
| else |
| { |
| return Result; |
| } |
| |
| /* we'll never need a temp string longer than the original */ |
| TempStrPtr = TempStr = (LPSTR) InternalMalloc(PAL_wcslen(*Fmt)+1); |
| if (!TempStr) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| return Result; |
| } |
| |
| /* parse flags */ |
| while (**Fmt && (**Fmt == '-' || **Fmt == '+' || |
| **Fmt == '0' || **Fmt == ' ' || **Fmt == '#')) |
| { |
| switch (**Fmt) |
| { |
| case '-': |
| *Flags |= PFF_MINUS; break; |
| case '+': |
| *Flags |= PFF_PLUS; break; |
| case '0': |
| *Flags |= PFF_ZERO; break; |
| case ' ': |
| *Flags |= PFF_SPACE; break; |
| case '#': |
| *Flags |= PFF_POUND; break; |
| } |
| *Out++ = (CHAR) *(*Fmt)++; |
| } |
| /* '-' flag negates '0' flag */ |
| if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO)) |
| { |
| *Flags -= PFF_ZERO; |
| } |
| |
| /* grab width specifier */ |
| if (isdigit(**Fmt)) |
| { |
| TempStrPtr = TempStr; |
| while (isdigit(**Fmt)) |
| { |
| *TempStrPtr++ = (CHAR) **Fmt; |
| *Out++ = (CHAR) *(*Fmt)++; |
| } |
| *TempStrPtr = 0; /* end string */ |
| *Width = atoi(TempStr); |
| if (*Width < 0) |
| { |
| ERROR("atoi returned a negative value indicative of an overflow.\n"); |
| pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); |
| return Result; |
| } |
| } |
| else if (**Fmt == '*') |
| { |
| *Width = WIDTH_STAR; |
| *Out++ = (CHAR) *(*Fmt)++; |
| if (isdigit(**Fmt)) |
| { |
| /* this is an invalid width because we have a * then a number */ |
| /* printf handles this by just printing the whole string */ |
| *Width = WIDTH_INVALID; |
| while (isdigit(**Fmt)) |
| { |
| *Out++ = (CHAR) *(*Fmt)++; |
| } |
| } |
| } |
| |
| /* grab precision specifier */ |
| if (**Fmt == '.') |
| { |
| *Out++ = (CHAR) *(*Fmt)++; |
| if (isdigit(**Fmt)) |
| { |
| TempStrPtr = TempStr; |
| while (isdigit(**Fmt)) |
| { |
| *TempStrPtr++ = (CHAR) **Fmt; |
| *Out++ = (CHAR) *(*Fmt)++; |
| } |
| *TempStrPtr = 0; /* end string */ |
| *Precision = atoi(TempStr); |
| if (*Precision < 0) |
| { |
| ERROR("atoi returned a negative value indicative of an overflow.\n"); |
| pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR); |
| return Result; |
| } |
| } |
| else if (**Fmt == '*') |
| { |
| *Precision = PRECISION_STAR; |
| *Out++ = (CHAR) *(*Fmt)++; |
| if (isdigit(**Fmt)) |
| { |
| /* this is an invalid precision because we have a .* then a number */ |
| /* printf handles this by just printing the whole string */ |
| *Precision = PRECISION_INVALID; |
| while (isdigit(**Fmt)) |
| { |
| *Out++ = (CHAR) *(*Fmt)++; |
| } |
| } |
| } |
| else |
| { |
| *Precision = PRECISION_DOT; |
| } |
| } |
| |
| #ifdef BIT64 |
| if (**Fmt == 'p') |
| { |
| *Prefix = PFF_PREFIX_LONGLONG; |
| } |
| #endif |
| if ((*Fmt)[0] == 'I') |
| { |
| /* grab prefix of 'I64' for __int64 */ |
| if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4') |
| { |
| /* convert to 'll' so that Unix snprintf can handle it */ |
| *Fmt += 3; |
| *Prefix = PFF_PREFIX_LONGLONG; |
| } |
| /* grab prefix of 'I32' for __int32 */ |
| else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2') |
| { |
| *Fmt += 3; |
| } |
| else |
| { |
| ++(*Fmt); |
| #ifdef BIT64 |
| /* convert to 'll' so that Unix snprintf can handle it */ |
| *Prefix = PFF_PREFIX_LONGLONG; |
| #endif |
| } |
| } |
| /* grab a prefix of 'h' */ |
| else if (**Fmt == 'h') |
| { |
| *Prefix = PFF_PREFIX_SHORT; |
| ++(*Fmt); |
| } |
| else if (**Fmt == 'l' || **Fmt == 'w') |
| { |
| ++(*Fmt); |
| #ifdef BIT64 |
| // Only want to change the prefix on 64 bit when printing characters. |
| if (**Fmt == 'C' || **Fmt == 'S') |
| #endif |
| { |
| *Prefix = PFF_PREFIX_LONG_W; |
| } |
| if (**Fmt == 'l') |
| { |
| *Prefix = PFF_PREFIX_LONGLONG; |
| ++(*Fmt); |
| } |
| } |
| else if (**Fmt == 'L') |
| { |
| /* a prefix of 'L' seems to be ignored */ |
| ++(*Fmt); |
| } |
| |
| |
| /* grab type 'c' */ |
| if (**Fmt == 'c' || **Fmt == 'C') |
| { |
| *Type = PFF_TYPE_CHAR; |
| if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'c') |
| { |
| *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ |
| } |
| if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W) |
| { |
| *Out++ = 'l'; |
| *Prefix = PFF_PREFIX_LONG; |
| } |
| *Out++ = 'c'; |
| ++(*Fmt); |
| Result = TRUE; |
| } |
| /* grab type 's' */ |
| else if (**Fmt == 's' || **Fmt == 'S' ) |
| { |
| if ( **Fmt == 'S' ) |
| { |
| *Type = PFF_TYPE_WSTRING; |
| } |
| else |
| { |
| *Type = PFF_TYPE_STRING; |
| } |
| if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 's') |
| { |
| *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */ |
| } |
| if (*Prefix == PFF_PREFIX_LONG) |
| { |
| *Out++ = 'l'; |
| } |
| |
| *Out++ = 's'; |
| ++(*Fmt); |
| Result = TRUE; |
| } |
| /* grab int types */ |
| else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' || |
| **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X') |
| { |
| *Type = PFF_TYPE_INT; |
| if (*Prefix == PFF_PREFIX_SHORT) |
| { |
| *Out++ = 'h'; |
| } |
| else if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W) |
| { |
| *Out++ = 'l'; |
| *Prefix = PFF_PREFIX_LONG; |
| } |
| else if (*Prefix == PFF_PREFIX_LONGLONG) |
| { |
| *Out++ = 'l'; |
| *Out++ = 'l'; |
| } |
| *Out++ = *(*Fmt)++; |
| Result = TRUE; |
| } |
| else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' || |
| **Fmt == 'g' || **Fmt == 'G') |
| { |
| /* we can safely ignore the prefixes and only add the type*/ |
| if (*Prefix == PFF_PREFIX_LONG_W) |
| { |
| *Prefix = PFF_PREFIX_LONG; |
| } |
| |
| *Type = PFF_TYPE_FLOAT; |
| *Out++ = *(*Fmt)++; |
| Result = TRUE; |
| } |
| else if (**Fmt == 'n') |
| { |
| if (*Prefix == PFF_PREFIX_LONG_W) |
| { |
| *Prefix = PFF_PREFIX_LONG; |
| } |
| |
| if (*Prefix == PFF_PREFIX_SHORT) |
| { |
| *Out++ = 'h'; |
| } |
| *Out++ = *(*Fmt)++; |
| *Type = PFF_TYPE_N; |
| Result = TRUE; |
| } |
| else if (**Fmt == 'p') |
| { |
| *Type = PFF_TYPE_P; |
| (*Fmt)++; |
| |
| if (*Prefix == PFF_PREFIX_LONGLONG) |
| { |
| if (*Precision == PRECISION_DEFAULT) |
| { |
| *Precision = 16; |
| *Out++ = '.'; |
| *Out++ = '1'; |
| *Out++ = '6'; |
| } |
| /* native *printf does not support %I64p |
| (actually %llp), so we need to cheat a little bit */ |
| *Out++ = 'l'; |
| *Out++ = 'l'; |
| } |
| else |
| { |
| if (*Precision == PRECISION_DEFAULT) |
| { |
| *Precision = 8; |
| *Out++ = '.'; |
| *Out++ = '8'; |
| } |
| if (*Prefix == PFF_PREFIX_LONG_W) |
| { |
| *Prefix = PFF_PREFIX_LONG; |
| } |
| } |
| *Out++ = 'X'; |
| Result = TRUE; |
| } |
| |
| *Out = 0; /* end the string */ |
| InternalFree(TempStr); |
| return Result; |
| } |
| |
| /******************************************************************************* |
| Function: |
| Internal_AddPaddingW |
| |
| Parameters: |
| Out |
| - buffer to place padding and given string (In) |
| Count |
| - maximum chars to be copied so as not to overrun given buffer |
| In |
| - string to place into (Out) accompanied with padding |
| Padding |
| - number of padding chars to add |
| Flags |
| - padding style flags (PRINTF_FORMAT_FLAGS) |
| *******************************************************************************/ |
| |
| BOOL Internal_AddPaddingW(LPWSTR *Out, INT Count, LPWSTR In, INT Padding, INT Flags) |
| { |
| LPWSTR OutOriginal = *Out; |
| INT PaddingOriginal = Padding; |
| INT LengthInStr; |
| LengthInStr = PAL_wcslen(In); |
| |
| |
| if (Padding < 0) |
| { |
| /* this is used at the bottom to determine if the buffer ran out */ |
| PaddingOriginal = 0; |
| } |
| if (Flags & PFF_MINUS) /* pad on right */ |
| { |
| if (wcsncpy_s(*Out, Count, In, min(LengthInStr + 1, Count - 1)) != SAFECRT_SUCCESS) |
| { |
| return FALSE; |
| } |
| |
| *Out += min(LengthInStr, Count - 1); |
| } |
| if (Padding > 0) |
| { |
| if (Flags & PFF_ZERO) /* '0', pad with zeros */ |
| { |
| while (Padding-- && Count > *Out - OutOriginal) |
| { |
| *(*Out)++ = '0'; |
| } |
| } |
| else /* pad left with spaces */ |
| { |
| while (Padding-- && Count > *Out - OutOriginal) |
| { |
| *(*Out)++ = ' '; |
| } |
| } |
| } |
| if (!(Flags & PFF_MINUS)) /* put 'In' after padding */ |
| { |
| if (wcsncpy_s(*Out, Count - (*Out - OutOriginal), In, |
| min(LengthInStr, Count - (*Out - OutOriginal) - 1)) != SAFECRT_SUCCESS) |
| { |
| return FALSE; |
| } |
| |
| *Out += min(LengthInStr, Count - (*Out - OutOriginal) - 1); |
| } |
| |
| if (LengthInStr + PaddingOriginal > Count - 1) |
| { |
| return FALSE; |
| } |
| else |
| { |
| return TRUE; |
| } |
| } |
| |
| /******************************************************************************* |
| Function: |
| Internal_AddPaddingVfprintf |
| |
| Parameters: |
| stream |
| - file stream to place padding and given string (In) |
| In |
| - string to place into (Out) accompanied with padding |
| Padding |
| - number of padding chars to add |
| Flags |
| - padding style flags (PRINTF_FORMAT_FLAGS) |
| *******************************************************************************/ |
| |
| INT Internal_AddPaddingVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPSTR In, |
| INT Padding, INT Flags) |
| { |
| LPSTR Out; |
| INT LengthInStr; |
| INT Length; |
| LPSTR OutOriginal; |
| INT Written; |
| |
| LengthInStr = strlen(In); |
| Length = LengthInStr; |
| |
| if (Padding > 0) |
| { |
| Length += Padding; |
| } |
| Out = (LPSTR) InternalMalloc(Length+1); |
| int iLength = Length+1; |
| if (!Out) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| return -1; |
| } |
| OutOriginal = Out; |
| |
| if (Flags & PFF_MINUS) /* pad on right */ |
| { |
| if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS) |
| { |
| ERROR("strcpy_s failed\n"); |
| pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); |
| Written = -1; |
| goto Done; |
| } |
| |
| Out += LengthInStr; |
| iLength -= LengthInStr; |
| } |
| if (Padding > 0) |
| { |
| iLength -= Padding; |
| if (Flags & PFF_ZERO) /* '0', pad with zeros */ |
| { |
| while (Padding--) |
| { |
| *Out++ = '0'; |
| } |
| } |
| else /* pad with spaces */ |
| { |
| while (Padding--) |
| { |
| *Out++ = ' '; |
| } |
| } |
| } |
| if (!(Flags & PFF_MINUS)) /* put 'In' after padding */ |
| { |
| if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS) |
| { |
| ERROR("strcpy_s failed\n"); |
| pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); |
| Written = -1; |
| goto Done; |
| } |
| |
| Out += LengthInStr; |
| iLength -= LengthInStr; |
| } |
| |
| #if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL |
| clearerr (stream->bsdFilePtr); |
| #endif |
| |
| Written = InternalFwrite(OutOriginal, 1, Length, stream->bsdFilePtr, &stream->PALferrorCode); |
| if (stream->PALferrorCode == PAL_FILE_ERROR) |
| { |
| ERROR("fwrite() failed with errno == %d\n", errno); |
| } |
| |
| Done: |
| InternalFree(OutOriginal); |
| |
| return Written; |
| } |
| |
| /******************************************************************************* |
| Function: |
| Internal_AddPaddingVfwprintf |
| |
| Parameters: |
| stream |
| - file stream to place padding and given string (In) |
| In |
| - string to place into (Out) accompanied with padding |
| Padding |
| - number of padding chars to add |
| Flags |
| - padding style flags (PRINTF_FORMAT_FLAGS) |
| *******************************************************************************/ |
| static INT Internal_AddPaddingVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPWSTR In, |
| INT Padding, INT Flags,BOOL convert) |
| { |
| LPWSTR Out; |
| LPWSTR OutOriginal; |
| INT LengthInStr; |
| INT Length; |
| INT Written = 0; |
| |
| LengthInStr = PAL_wcslen(In); |
| Length = LengthInStr; |
| |
| if (Padding > 0) |
| { |
| Length += Padding; |
| } |
| |
| int iLen = (Length+1); |
| Out = (LPWSTR) InternalMalloc(iLen * sizeof(WCHAR)); |
| if (!Out) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| return -1; |
| } |
| OutOriginal = Out; |
| |
| if (Flags & PFF_MINUS) /* pad on right */ |
| { |
| if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS) |
| { |
| ERROR("wcscpy_s failed!\n"); |
| InternalFree(OutOriginal); |
| pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); |
| return -1; |
| } |
| Out += LengthInStr; |
| iLen -= LengthInStr; |
| } |
| if (Padding > 0) |
| { |
| iLen -= Padding; |
| if (Flags & PFF_ZERO) /* '0', pad with zeros */ |
| { |
| while (Padding--) |
| { |
| *Out++ = '0'; |
| } |
| } |
| else /* pad with spaces */ |
| { |
| while (Padding--) |
| { |
| *Out++ = ' '; |
| } |
| } |
| } |
| if (!(Flags & PFF_MINUS)) /* put 'In' after padding */ |
| { |
| if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS) |
| { |
| ERROR("wcscpy_s failed!\n"); |
| InternalFree(OutOriginal); |
| pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER); |
| return -1; |
| } |
| |
| Out += LengthInStr; |
| iLen -= LengthInStr; |
| } |
| |
| if (Length > 0) { |
| Written = Internal_Convertfwrite(pthrCurrent, OutOriginal, sizeof(char16_t), Length, |
| (FILE*)(stream->bsdFilePtr), convert); |
| |
| if (-1 == Written) |
| { |
| ERROR("fwrite() failed with errno == %d\n", errno); |
| } |
| } |
| InternalFree(OutOriginal); |
| |
| return Written; |
| } |
| |
| /******************************************************************************* |
| Function: |
| PAL_vsnprintf |
| |
| Parameters: |
| Buffer |
| - out buffer |
| Count |
| - buffer size |
| Format |
| - format string |
| ap |
| - stdarg parameter list |
| *******************************************************************************/ |
| |
| int __cdecl PAL__vsnprintf(LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap) |
| { |
| return CoreVsnprintf(InternalGetCurrentThread(), Buffer, Count, Format, ap); |
| } |
| |
| /******************************************************************************* |
| Function: |
| PAL_wvsnprintf |
| |
| -- see PAL_vsnprintf above |
| *******************************************************************************/ |
| |
| int __cdecl PAL__wvsnprintf(LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list ap) |
| { |
| return CoreWvsnprintf(InternalGetCurrentThread(), Buffer, Count, Format, ap); |
| } |
| |
| /******************************************************************************* |
| Function: |
| PAL_vfprintf |
| |
| Parameters: |
| stream |
| - out stream |
| Format |
| - format string |
| ap |
| - stdarg parameter list |
| *******************************************************************************/ |
| |
| int __cdecl PAL_vfprintf(PAL_FILE *stream, const char *format, va_list ap) |
| { |
| return CoreVfprintf(InternalGetCurrentThread(), stream, format, ap); |
| } |
| |
| /******************************************************************************* |
| Function: |
| PAL_vfwprintf |
| |
| Parameters: |
| stream |
| - out stream |
| Format |
| - format string |
| ap |
| - stdarg parameter list |
| *******************************************************************************/ |
| |
| int __cdecl PAL_vfwprintf(PAL_FILE *stream, const char16_t *format, va_list ap) |
| { |
| return CoreVfwprintf(InternalGetCurrentThread(), stream, format, ap); |
| } |
| |
| } // end extern "C" |
| |
| int CorUnix::InternalWvsnprintf(CPalThread *pthrCurrent, LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list ap) |
| { |
| return CoreWvsnprintf(pthrCurrent, Buffer, Count, Format, ap); |
| } |
| |
| int CorUnix::InternalVsnprintf(CPalThread *pthrCurrent, LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap) |
| { |
| return CoreVsnprintf(pthrCurrent, Buffer, Count, Format, ap); |
| } |
| |
| int CorUnix::InternalVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap) |
| { |
| return CoreVfprintf(pthrCurrent, stream, format, ap); |
| } |
| |
| int CorUnix::InternalVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char16_t *format, va_list ap) |
| { |
| return CoreVfwprintf(pthrCurrent, stream, format, ap); |
| } |
| |
| int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char16_t *format, va_list aparg) |
| { |
| CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */ |
| LPCWSTR Fmt = format; |
| LPWSTR TempWStr = NULL; |
| LPWSTR WorkingWStr = NULL; |
| WCHAR TempWChar[2]; |
| INT Flags; |
| INT Width; |
| INT Precision; |
| INT Prefix; |
| INT Type; |
| INT TempInt; |
| BOOL WStrWasMalloced = FALSE; |
| int mbtowcResult; |
| int written=0; |
| int paddingReturnValue; |
| int ret; |
| va_list ap; |
| |
| /* fwprintf for now in the PAL is always used on file opened |
| in text mode. In those case the output should be ANSI not Unicode */ |
| BOOL textMode = TRUE; |
| |
| PERF_ENTRY(vfwprintf); |
| ENTRY("vfwprintf (stream=%p, format=%p (%S))\n", |
| stream, format, format); |
| |
| va_copy(ap, aparg); |
| |
| while (*Fmt) |
| { |
| if(*Fmt == '%' && |
| TRUE == Internal_ExtractFormatW(pthrCurrent, &Fmt, TempBuff, &Flags, |
| &Width, &Precision, |
| &Prefix, &Type)) |
| { |
| if (((Prefix == PFF_PREFIX_LONG || Prefix == PFF_PREFIX_LONG_W) && |
| (Type == PFF_TYPE_STRING || Type == PFF_TYPE_WSTRING)) || |
| (Type == PFF_TYPE_WSTRING && (Flags & PFF_ZERO) != 0)) |
| { |
| WStrWasMalloced = FALSE; |
| |
| if (WIDTH_STAR == Width) |
| { |
| Width = va_arg(ap, INT); |
| } |
| else if (WIDTH_INVALID == Width) |
| { |
| /* both a '*' and a number, ignore, but remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| if (PRECISION_STAR == Precision) |
| { |
| Precision = va_arg(ap, INT); |
| } |
| else if (PRECISION_INVALID == Precision) |
| { |
| /* both a '*' and a number, ignore, but remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| if (Type == PFF_TYPE_STRING || Prefix == PFF_PREFIX_LONG_W) |
| { |
| TempWStr = va_arg(ap, LPWSTR); |
| } |
| else |
| { |
| /* %lS assumes a LPSTR argument. */ |
| LPSTR s = va_arg(ap, LPSTR ); |
| UINT Length = 0; |
| Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 ); |
| if ( Length != 0 ) |
| { |
| TempWStr = |
| (LPWSTR)InternalMalloc( (Length) * sizeof( WCHAR ) ); |
| if ( TempWStr ) |
| { |
| WStrWasMalloced = TRUE; |
| MultiByteToWideChar( CP_ACP, 0, s, -1, |
| TempWStr, Length ); |
| } |
| else |
| { |
| ERROR( "InternalMalloc failed.\n" ); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| va_end(ap); |
| return -1; |
| } |
| } |
| else |
| { |
| ASSERT( "Unable to convert from multibyte " |
| " to wide char.\n" ); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| va_end(ap); |
| return -1; |
| } |
| } |
| |
| INT Length = PAL_wcslen(TempWStr); |
| WorkingWStr = (LPWSTR) InternalMalloc((sizeof(WCHAR) * (Length + 1))); |
| if (!WorkingWStr) |
| { |
| ERROR("InternalMalloc failed\n"); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| if (WStrWasMalloced) |
| { |
| InternalFree(TempWStr); |
| } |
| va_end(ap); |
| return -1; |
| } |
| if (PRECISION_DOT == Precision) |
| { |
| /* copy nothing */ |
| *WorkingWStr = 0; |
| Length = 0; |
| } |
| else if (Precision > 0 && Precision < Length) |
| { |
| if (wcsncpy_s(WorkingWStr, (Length + 1), TempWStr, Precision+1) != SAFECRT_SUCCESS) |
| { |
| ERROR("Internal_AddPaddingVfwprintf failed\n"); |
| if (WStrWasMalloced) |
| { |
| InternalFree(TempWStr); |
| } |
| InternalFree(WorkingWStr); |
| LOGEXIT("wcsncpy_s failed!\n"); |
| PERF_EXIT(vfwprintf); |
| va_end(ap); |
| return (-1); |
| } |
| |
| Length = Precision; |
| } |
| /* copy everything */ |
| else |
| { |
| PAL_wcscpy(WorkingWStr, TempWStr); |
| } |
| |
| |
| /* do the padding (if needed)*/ |
| paddingReturnValue = |
| Internal_AddPaddingVfwprintf( pthrCurrent, stream, WorkingWStr, |
| Width - Length, |
| Flags,textMode); |
| |
| if (paddingReturnValue == -1) |
| { |
| ERROR("Internal_AddPaddingVfwprintf failed\n"); |
| if (WStrWasMalloced) |
| { |
| InternalFree(TempWStr); |
| } |
| InternalFree(WorkingWStr); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| va_end(ap); |
| return (-1); |
| } |
| written += paddingReturnValue; |
| |
| InternalFree(WorkingWStr); |
| if (WStrWasMalloced) |
| { |
| InternalFree(TempWStr); |
| } |
| } |
| else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR) |
| { |
| if (WIDTH_STAR == Width || |
| WIDTH_INVALID == Width) |
| { |
| /* ignore (because it's a char), and remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| if (PRECISION_STAR == Precision || |
| PRECISION_INVALID == Precision) |
| { |
| /* ignore (because it's a char), and remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| TempWChar[0] = va_arg(ap, int); |
| TempWChar[1] = 0; |
| |
| /* do the padding (if needed)*/ |
| paddingReturnValue = |
| Internal_AddPaddingVfwprintf(pthrCurrent, stream, TempWChar, |
| Width - 1, |
| Flags,textMode); |
| if (paddingReturnValue == -1) |
| { |
| ERROR("Internal_AddPaddingVfwprintf failed\n"); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| va_end(ap); |
| return(-1); |
| } |
| written += paddingReturnValue; |
| } |
| /* this places the number of bytes written to the buffer in the |
| next arg */ |
| else if (Type == PFF_TYPE_N) |
| { |
| if (WIDTH_STAR == Width) |
| { |
| Width = va_arg(ap, INT); |
| } |
| |
| if (PRECISION_STAR == Precision) |
| { |
| Precision = va_arg(ap, INT); |
| } |
| |
| if (Prefix == PFF_PREFIX_SHORT) |
| { |
| *(va_arg(ap, short *)) = written; |
| } |
| else |
| { |
| *(va_arg(ap, LPLONG)) = written; |
| } |
| } |
| else |
| { |
| // Types that sprintf can handle. |
| |
| /* note: I'm using the wide buffer as a (char *) buffer when I |
| pass it to sprintf(). After I get the buffer back I make a |
| backup of the chars copied and then convert them to wide |
| and place them in the buffer (BufferPtr) */ |
| |
| // This argument will be limited to 1024 characters. |
| // It should be enough. |
| size_t TEMP_COUNT = 1024; |
| char TempSprintfStrBuffer[1024]; |
| char *TempSprintfStrPtr = NULL; |
| char *TempSprintfStr = TempSprintfStrBuffer; |
| LPWSTR TempWideBuffer; |
| |
| TempInt = 0; |
| // %h (short) doesn't seem to be handled properly by local sprintf, |
| // so we do the truncation ourselves for some cases. |
| if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT) |
| { |
| // Convert from pointer -> int -> short to avoid warnings. |
| long trunc1; |
| short trunc2; |
| |
| trunc1 = va_arg(ap, LONG); |
| trunc2 = (short)trunc1; |
| trunc1 = trunc2; |
| |
| TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, trunc1); |
| |
| if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT) |
| { |
| if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt))) |
| { |
| ERROR("InternalMalloc failed\n"); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| va_end(ap); |
| return -1; |
| } |
| |
| TempSprintfStr = TempSprintfStrPtr; |
| snprintf(TempSprintfStr, TempInt, TempBuff, trunc2); |
| } |
| } |
| else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT) |
| { |
| // Convert explicitly from int to short to get |
| // correct sign extension for shorts on all systems. |
| int n; |
| short s; |
| |
| n = va_arg(ap, int); |
| s = (short) n; |
| |
| TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, s); |
| |
| if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT) |
| { |
| if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt))) |
| { |
| ERROR("InternalMalloc failed\n"); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| va_end(ap); |
| return -1; |
| } |
| |
| TempSprintfStr = TempSprintfStrPtr; |
| snprintf(TempSprintfStr, TempInt, TempBuff, s); |
| } |
| } |
| else |
| { |
| va_list apcopy; |
| |
| va_copy(apcopy, ap); |
| TempInt = vsnprintf(TempSprintfStr, TEMP_COUNT, TempBuff, apcopy); |
| va_end(apcopy); |
| PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); |
| |
| if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT) |
| { |
| if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt))) |
| { |
| ERROR("InternalMalloc failed\n"); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| va_end(ap); |
| return -1; |
| } |
| |
| TempSprintfStr = TempSprintfStrPtr; |
| va_copy(apcopy, ap); |
| vsnprintf(TempSprintfStr, TempInt, TempBuff, apcopy); |
| va_end(apcopy); |
| PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); |
| } |
| } |
| |
| mbtowcResult = MultiByteToWideChar(CP_ACP, 0, |
| TempSprintfStr, -1, |
| NULL, 0); |
| |
| if (mbtowcResult == 0) |
| { |
| ERROR("MultiByteToWideChar failed\n"); |
| if(TempSprintfStrPtr) |
| { |
| InternalFree(TempSprintfStrPtr); |
| } |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| va_end(ap); |
| return -1; |
| } |
| |
| TempWideBuffer = (LPWSTR) InternalMalloc(mbtowcResult*sizeof(WCHAR)); |
| if (!TempWideBuffer) |
| { |
| ERROR("InternalMalloc failed\n"); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| if(TempSprintfStrPtr) |
| { |
| InternalFree(TempSprintfStrPtr); |
| } |
| va_end(ap); |
| return -1; |
| } |
| |
| MultiByteToWideChar(CP_ACP, 0, TempSprintfStr, -1, |
| TempWideBuffer, mbtowcResult); |
| |
| ret = Internal_Convertfwrite( |
| pthrCurrent, |
| TempWideBuffer, |
| sizeof(char16_t), |
| mbtowcResult-1, |
| (FILE*)stream->bsdFilePtr, |
| textMode); |
| |
| if (-1 == ret) |
| { |
| ERROR("fwrite() failed with errno == %d (%s)\n", errno, strerror(errno)); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| InternalFree(TempWideBuffer); |
| if(TempSprintfStrPtr) |
| { |
| InternalFree(TempSprintfStrPtr); |
| } |
| va_end(ap); |
| return -1; |
| } |
| if(TempSprintfStrPtr) |
| { |
| InternalFree(TempSprintfStrPtr); |
| } |
| InternalFree(TempWideBuffer); |
| } |
| } |
| else |
| { |
| ret = Internal_Convertfwrite( |
| pthrCurrent, |
| Fmt++, |
| sizeof(char16_t), |
| 1, |
| (FILE*)stream->bsdFilePtr, |
| textMode); /* copy regular chars into buffer */ |
| |
| if (-1 == ret) |
| { |
| ERROR("fwrite() failed with errno == %d\n", errno); |
| LOGEXIT("vfwprintf returns int -1\n"); |
| PERF_EXIT(vfwprintf); |
| va_end(ap); |
| return -1; |
| } |
| ++written; |
| } |
| } |
| |
| LOGEXIT("vfwprintf returns int %d\n", written); |
| PERF_EXIT(vfwprintf); |
| va_end(ap); |
| return (written); |
| } |
| |
| int CoreVsnprintf(CPalThread *pthrCurrent, LPSTR Buffer, size_t Count, LPCSTR Format, va_list aparg) |
| { |
| BOOL BufferRanOut = FALSE; |
| CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */ |
| LPSTR BufferPtr = Buffer; |
| LPCSTR Fmt = Format; |
| LPWSTR TempWStr; |
| LPSTR TempStr; |
| WCHAR TempWChar; |
| INT Flags; |
| INT Width; |
| INT Precision; |
| INT Prefix; |
| INT Type; |
| INT Length; |
| INT TempInt; |
| int wctombResult; |
| va_list ap; |
| |
| va_copy(ap, aparg); |
| |
| while (*Fmt) |
| { |
| if (BufferRanOut || (BufferPtr - Buffer) >= static_cast<int>(Count)) //Count is assumed to be in the range of int |
| { |
| BufferRanOut = TRUE; |
| break; |
| } |
| else if(*Fmt == '%' && |
| TRUE == Internal_ExtractFormatA(pthrCurrent, &Fmt, TempBuff, &Flags, |
| &Width, &Precision, |
| &Prefix, &Type)) |
| { |
| if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING) |
| { |
| if (WIDTH_STAR == Width) |
| { |
| Width = va_arg(ap, INT); |
| } |
| else if (WIDTH_INVALID == Width) |
| { |
| /* both a '*' and a number, ignore, but remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| if (PRECISION_STAR == Precision) |
| { |
| Precision = va_arg(ap, INT); |
| } |
| else if (PRECISION_INVALID == Precision) |
| { |
| /* both a '*' and a number, ignore, but remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| TempWStr = va_arg(ap, LPWSTR); |
| Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, 0, |
| 0, 0, 0); |
| if (!Length) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", |
| GetLastError()); |
| va_end(ap); |
| return -1; |
| } |
| TempStr = (LPSTR) InternalMalloc(Length); |
| if (!TempStr) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| va_end(ap); |
| return -1; |
| } |
| if (PRECISION_DOT == Precision) |
| { |
| /* copy nothing */ |
| *TempStr = 0; |
| Length = 0; |
| } |
| else if (Precision > 0 && Precision < Length - 1) |
| { |
| Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, |
| Precision, TempStr, Length, |
| 0, 0); |
| if (!Length) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", |
| GetLastError()); |
| InternalFree(TempStr); |
| va_end(ap); |
| return -1; |
| } |
| TempStr[Length] = 0; |
| Length = Precision; |
| } |
| /* copy everything */ |
| else |
| { |
| wctombResult = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, |
| TempStr, Length, 0, 0); |
| if (!wctombResult) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", |
| GetLastError()); |
| InternalFree(TempStr); |
| va_end(ap); |
| return -1; |
| } |
| --Length; /* exclude null char */ |
| } |
| |
| /* do the padding (if needed)*/ |
| BufferRanOut = !Internal_AddPaddingA(&BufferPtr, |
| Count - (BufferPtr - Buffer), |
| TempStr, |
| Width - Length, |
| Flags); |
| |
| InternalFree(TempStr); |
| } |
| else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR) |
| { |
| CHAR TempBuffer[5]; |
| |
| if (WIDTH_STAR == Width || |
| WIDTH_INVALID == Width) |
| { |
| /* ignore (because it's a char), and remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| if (PRECISION_STAR == Precision || |
| PRECISION_INVALID == Precision) |
| { |
| /* ignore (because it's a char), and remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| TempWChar = va_arg(ap, int); |
| Length = WideCharToMultiByte(CP_ACP, 0, &TempWChar, 1, |
| TempBuffer, sizeof(TempBuffer), |
| 0, 0); |
| if (!Length) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", |
| GetLastError()); |
| va_end(ap); |
| return -1; |
| } |
| TempBuffer[Length] = 0; |
| |
| /* do the padding (if needed)*/ |
| BufferRanOut = !Internal_AddPaddingA(&BufferPtr, |
| Count - (BufferPtr - Buffer), |
| TempBuffer, |
| Width - Length, |
| Flags); |
| |
| } |
| /* this places the number of bytes written to the buffer in the |
| next arg */ |
| else if (Type == PFF_TYPE_N) |
| { |
| if (WIDTH_STAR == Width) |
| { |
| Width = va_arg(ap, INT); |
| } |
| if (PRECISION_STAR == Precision) |
| { |
| Precision = va_arg(ap, INT); |
| } |
| |
| if (Prefix == PFF_PREFIX_SHORT) |
| { |
| *(va_arg(ap, short *)) = BufferPtr - Buffer; |
| } |
| else |
| { |
| *(va_arg(ap, LPLONG)) = BufferPtr - Buffer; |
| } |
| } |
| else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0) |
| { |
| // Some versions of sprintf don't support 0-padded chars, |
| // so we handle them here. |
| char ch[2]; |
| |
| ch[0] = (char) va_arg(ap, int); |
| ch[1] = '\0'; |
| Length = 1; |
| BufferRanOut = !Internal_AddPaddingA(&BufferPtr, |
| Count - (BufferPtr - Buffer), |
| ch, |
| Width - Length, |
| Flags); |
| } |
| else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0) |
| { |
| // Some versions of sprintf don't support 0-padded strings, |
| // so we handle them here. |
| char *tempStr; |
| |
| tempStr = va_arg(ap, char *); |
| Length = strlen(tempStr); |
| BufferRanOut = !Internal_AddPaddingA(&BufferPtr, |
| Count - (BufferPtr - Buffer), |
| tempStr, |
| Width - Length, |
| Flags); |
| } |
| else |
| { |
| // Types that sprintf can handle |
| size_t TempCount = Count - (BufferPtr - Buffer); |
| |
| #if !HAVE_LARGE_SNPRINTF_SUPPORT |
| // Limit TempCount to 0x40000000, which is sufficient |
| // for platforms on which snprintf fails for very large |
| // sizes. |
| if (TempCount > 0x40000000) |
| { |
| TempCount = 0x40000000; |
| } |
| #endif // HAVE_LARGE_SNPRINTF_SUPPORT |
| |
| TempInt = 0; |
| // %h (short) doesn't seem to be handled properly by local sprintf, |
| // so we do the truncation ourselves for some cases. |
| if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT) |
| { |
| // Convert from pointer -> int -> short to avoid warnings. |
| long trunc1; |
| short trunc2; |
| |
| trunc1 = va_arg(ap, LONG); |
| trunc2 = (short) trunc1; |
| trunc1 = trunc2; |
| |
| TempInt = snprintf(BufferPtr, TempCount, TempBuff, trunc1); |
| } |
| else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT) |
| { |
| // Convert explicitly from int to short to get |
| // correct sign extension for shorts on all systems. |
| int n; |
| short s; |
| |
| n = va_arg(ap, int); |
| s = (short) n; |
| |
| TempInt = snprintf(BufferPtr, TempCount, TempBuff, s); |
| } |
| else |
| { |
| va_list apcopy; |
| va_copy(apcopy, ap); |
| TempInt = vsnprintf(BufferPtr, TempCount, TempBuff, apcopy); |
| va_end(apcopy); |
| PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); |
| } |
| |
| if (TempInt < 0 || static_cast<size_t>(TempInt) >= TempCount) /* buffer not long enough */ |
| { |
| BufferPtr += TempCount; |
| BufferRanOut = TRUE; |
| } |
| else |
| { |
| BufferPtr += TempInt; |
| } |
| } |
| } |
| else |
| { |
| *BufferPtr++ = *Fmt++; /* copy regular chars into buffer */ |
| } |
| } |
| |
| if (static_cast<int>(Count) > (BufferPtr - Buffer)) //Count is assumed to be in the range of int |
| { |
| *BufferPtr = 0; /* end the string */ |
| } |
| |
| va_end(ap); |
| |
| if (BufferRanOut) |
| { |
| errno = ERANGE; |
| return -1; |
| } |
| else |
| { |
| return BufferPtr - Buffer; |
| } |
| } |
| |
| int CoreWvsnprintf(CPalThread *pthrCurrent, LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list aparg) |
| { |
| BOOL BufferRanOut = FALSE; |
| CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */ |
| LPWSTR BufferPtr = Buffer; |
| LPCWSTR Fmt = Format; |
| LPWSTR TempWStr = NULL; |
| LPWSTR WorkingWStr = NULL; |
| WCHAR TempWChar[2]; |
| INT Flags; |
| INT Width; |
| INT Precision; |
| INT Prefix; |
| INT Type; |
| INT TempInt; |
| LPSTR TempNumberBuffer; |
| int mbtowcResult; |
| va_list(ap); |
| |
| PERF_ENTRY(wvsnprintf); |
| ENTRY("wvsnprintf (buffer=%p, count=%u, format=%p (%S))\n", |
| Buffer, Count, Format, Format); |
| |
| va_copy(ap, aparg); |
| BOOL precisionSet = false; |
| |
| while (*Fmt) |
| { |
| if (BufferRanOut || (BufferPtr - Buffer) >= static_cast<int>(Count)) //Count is assumed to be in the range of int |
| { |
| BufferRanOut = TRUE; |
| break; |
| } |
| else if(*Fmt == '%' && |
| TRUE == Internal_ExtractFormatW(pthrCurrent, &Fmt, TempBuff, &Flags, |
| &Width, &Precision, |
| &Prefix, &Type)) |
| { |
| if (((Prefix == PFF_PREFIX_LONG || Prefix == PFF_PREFIX_LONG_W) && |
| (Type == PFF_TYPE_STRING || Type == PFF_TYPE_WSTRING)) || |
| (Prefix == PFF_PREFIX_SHORT && Type == PFF_TYPE_STRING) || |
| (Type == PFF_TYPE_WSTRING && (Flags & PFF_ZERO) != 0)) |
| { |
| BOOL needToFree = FALSE; |
| |
| if (WIDTH_STAR == Width) |
| { |
| Width = va_arg(ap, INT); |
| } |
| else if (WIDTH_INVALID == Width) |
| { |
| /* both a '*' and a number, ignore, but remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| if (PRECISION_STAR == Precision) |
| { |
| Precision = va_arg(ap, INT); |
| precisionSet = true; |
| } |
| else if (PRECISION_INVALID == Precision) |
| { |
| /* both a '*' and a number, ignore, but remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| if ((Type == PFF_TYPE_STRING && Prefix == PFF_PREFIX_LONG) || |
| Prefix == PFF_PREFIX_LONG_W) |
| { |
| TempWStr = va_arg(ap, LPWSTR); |
| } |
| else |
| { |
| // %lS and %hs assume an LPSTR argument. |
| LPSTR s = va_arg(ap, LPSTR ); |
| UINT Length = 0; |
| Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 ); |
| if ( Length != 0 ) |
| { |
| TempWStr = |
| (LPWSTR)InternalMalloc((Length + 1 ) * sizeof( WCHAR ) ); |
| if ( TempWStr ) |
| { |
| needToFree = TRUE; |
| MultiByteToWideChar( CP_ACP, 0, s, -1, |
| TempWStr, Length ); |
| } |
| else |
| { |
| ERROR( "InternalMalloc failed.\n" ); |
| va_end(ap); |
| return -1; |
| } |
| } |
| else |
| { |
| ASSERT( "Unable to convert from multibyte " |
| " to wide char.\n" ); |
| va_end(ap); |
| return -1; |
| } |
| } |
| |
| INT Length = 0; |
| if (precisionSet) |
| { |
| for(; Length <= Precision && TempWStr[Length] != 0; Length++); |
| } |
| else |
| { |
| Length = PAL_wcslen(TempWStr); |
| } |
| |
| WorkingWStr = (LPWSTR) InternalMalloc(sizeof(WCHAR) * (Length + 1)); |
| if (!WorkingWStr) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| if (needToFree) |
| { |
| InternalFree(TempWStr); |
| } |
| va_end(ap); |
| return -1; |
| } |
| if (PRECISION_DOT == Precision) |
| { |
| // Copy nothing |
| *WorkingWStr = 0; |
| Length = 0; |
| } |
| else if (Precision > 0 && Precision < Length) |
| { |
| if (wcsncpy_s(WorkingWStr, (Length + 1), TempWStr, Precision) != SAFECRT_SUCCESS) |
| { |
| ERROR("CoreWvsnprintf failed\n"); |
| if (needToFree) |
| { |
| InternalFree(TempWStr); |
| } |
| InternalFree(WorkingWStr); |
| LOGEXIT("wcsncpy_s failed!\n"); |
| PERF_EXIT(wvsnprintf); |
| va_end(ap); |
| return (-1); |
| } |
| Length = Precision; |
| } |
| else |
| { |
| // Copy everything |
| PAL_wcscpy(WorkingWStr, TempWStr); |
| } |
| |
| // Add padding if needed. |
| BufferRanOut = !Internal_AddPaddingW(&BufferPtr, |
| Count - (BufferPtr - Buffer), |
| WorkingWStr, |
| Width - Length, |
| Flags); |
| |
| if (needToFree) |
| { |
| InternalFree(TempWStr); |
| } |
| InternalFree(WorkingWStr); |
| } |
| else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR) |
| { |
| if (WIDTH_STAR == Width || |
| WIDTH_INVALID == Width) |
| { |
| /* ignore (because it's a char), and remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| if (PRECISION_STAR == Precision || |
| PRECISION_INVALID == Precision) |
| { |
| /* ignore (because it's a char), and remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| TempWChar[0] = va_arg(ap, int); |
| TempWChar[1] = 0; |
| |
| /* do the padding (if needed)*/ |
| BufferRanOut = !Internal_AddPaddingW(&BufferPtr, |
| Count - (BufferPtr - Buffer), |
| TempWChar, |
| Width - 1, |
| Flags); |
| |
| } |
| /* this places the number of bytes written to the buffer in the |
| next arg */ |
| else if (Type == PFF_TYPE_N) |
| { |
| if (WIDTH_STAR == Width) |
| { |
| Width = va_arg(ap, INT); |
| } |
| if (PRECISION_STAR == Precision) |
| { |
| Precision = va_arg(ap, INT); |
| } |
| |
| if (Prefix == PFF_PREFIX_SHORT) |
| { |
| *(va_arg(ap, short *)) = BufferPtr - Buffer; |
| } |
| else |
| { |
| *(va_arg(ap, LPLONG)) = BufferPtr - Buffer; |
| } |
| } |
| else |
| { |
| // Types that sprintf can handle |
| |
| /* note: I'm using the wide buffer as a (char *) buffer when I |
| pass it to sprintf(). After I get the buffer back I make a |
| backup of the chars copied and then convert them to wide |
| and place them in the buffer (BufferPtr) */ |
| size_t TempCount = Count - (BufferPtr - Buffer); |
| TempInt = 0; |
| |
| #if !HAVE_LARGE_SNPRINTF_SUPPORT |
| // Limit TempCount to 0x40000000, which is sufficient |
| // for platforms on which snprintf fails for very large |
| // sizes. |
| if (TempCount > 0x40000000) |
| { |
| TempCount = 0x40000000; |
| } |
| #endif // HAVE_LARGE_SNPRINTF_SUPPORT |
| |
| // %h (short) doesn't seem to be handled properly by local sprintf, |
| // so we do the truncation ourselves for some cases. |
| if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT) |
| { |
| // Convert from pointer -> int -> short to avoid warnings. |
| long trunc1; |
| short trunc2; |
| |
| trunc1 = va_arg(ap, LONG); |
| trunc2 = (short)trunc1; |
| trunc1 = trunc2; |
| |
| TempInt = snprintf((LPSTR)BufferPtr, TempCount, TempBuff, trunc1); |
| } |
| else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT) |
| { |
| // Convert explicitly from int to short to get |
| // correct sign extension for shorts on all systems. |
| int n; |
| short s; |
| |
| n = va_arg(ap, int); |
| s = (short) n; |
| |
| TempInt = snprintf((LPSTR)BufferPtr, TempCount, TempBuff, s); |
| } |
| else |
| { |
| va_list apcopy; |
| va_copy(apcopy, ap); |
| TempInt = vsnprintf((LPSTR) BufferPtr, TempCount, TempBuff, apcopy); |
| va_end(apcopy); |
| PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); |
| } |
| |
| if (TempInt == 0) |
| { |
| // The argument is "". |
| continue; |
| } |
| if (TempInt < 0 || static_cast<size_t>(TempInt) >= TempCount) /* buffer not long enough */ |
| { |
| TempNumberBuffer = (LPSTR) InternalMalloc(TempCount+1); |
| if (!TempNumberBuffer) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| errno = ENOMEM; |
| va_end(ap); |
| return -1; |
| } |
| |
| if (strncpy_s(TempNumberBuffer, TempCount+1, (LPSTR) BufferPtr, TempCount) != SAFECRT_SUCCESS) |
| { |
| ASSERT("strncpy_s failed!\n"); |
| InternalFree(TempNumberBuffer); |
| va_end(ap); |
| return -1; |
| } |
| |
| mbtowcResult = MultiByteToWideChar(CP_ACP, 0, |
| TempNumberBuffer, |
| TempCount, |
| BufferPtr, TempCount); |
| if (!mbtowcResult) |
| { |
| ASSERT("MultiByteToWideChar failed. Error is %d\n", |
| GetLastError()); |
| InternalFree(TempNumberBuffer); |
| va_end(ap); |
| return -1; |
| } |
| BufferPtr += TempCount; |
| BufferRanOut = TRUE; |
| } |
| else |
| { |
| TempNumberBuffer = (LPSTR) InternalMalloc(TempInt+1); |
| if (!TempNumberBuffer) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| va_end(ap); |
| return -1; |
| } |
| |
| if (strncpy_s(TempNumberBuffer, TempInt+1, (LPSTR) BufferPtr, TempInt) != SAFECRT_SUCCESS) |
| { |
| ASSERT("strncpy_s failed!\n"); |
| InternalFree(TempNumberBuffer); |
| va_end(ap); |
| return -1; |
| } |
| |
| mbtowcResult = MultiByteToWideChar(CP_ACP, 0, |
| TempNumberBuffer, |
| TempInt, |
| BufferPtr, TempInt); |
| if (!mbtowcResult) |
| { |
| ASSERT("MultiByteToWideChar failed. Error is %d\n", |
| GetLastError()); |
| InternalFree(TempNumberBuffer); |
| va_end(ap); |
| return -1; |
| } |
| BufferPtr += TempInt; |
| } |
| InternalFree(TempNumberBuffer); |
| } |
| } |
| else |
| { |
| *BufferPtr++ = *Fmt++; /* copy regular chars into buffer */ |
| } |
| } |
| |
| if (static_cast<int>(Count) > (BufferPtr - Buffer)) //Count is assumed to be in the range of int |
| { |
| *BufferPtr = 0; /* end the string */ |
| } |
| |
| va_end(ap); |
| |
| if (BufferRanOut) |
| { |
| errno = ERANGE; |
| return -1; |
| } |
| else |
| { |
| return BufferPtr - Buffer; |
| } |
| } |
| |
| int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list aparg) |
| { |
| CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */ |
| LPCSTR Fmt = format; |
| LPWSTR TempWStr; |
| LPSTR TempStr; |
| WCHAR TempWChar; |
| INT Flags; |
| INT Width; |
| INT Precision; |
| INT Prefix; |
| INT Type; |
| INT Length; |
| INT TempInt; |
| int wctombResult; |
| int written = 0; |
| int paddingReturnValue; |
| va_list ap; |
| |
| PERF_ENTRY(vfprintf); |
| |
| va_copy(ap, aparg); |
| |
| while (*Fmt) |
| { |
| if (*Fmt == '%' && |
| TRUE == Internal_ExtractFormatA(pthrCurrent, &Fmt, TempBuff, &Flags, |
| &Width, &Precision, |
| &Prefix, &Type)) |
| { |
| if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING) |
| { |
| if (WIDTH_STAR == Width) |
| { |
| Width = va_arg(ap, INT); |
| } |
| else if (WIDTH_INVALID == Width) |
| { |
| /* both a '*' and a number, ignore, but remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| if (PRECISION_STAR == Precision) |
| { |
| Precision = va_arg(ap, INT); |
| } |
| else if (PRECISION_INVALID == Precision) |
| { |
| /* both a '*' and a number, ignore, but remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| TempWStr = va_arg(ap, LPWSTR); |
| Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, 0, |
| 0, 0, 0); |
| if (!Length) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", |
| GetLastError()); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| TempStr = (LPSTR) InternalMalloc(Length); |
| if (!TempStr) |
| { |
| ERROR("InternalMalloc failed\n"); |
| pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| if (PRECISION_DOT == Precision) |
| { |
| /* copy nothing */ |
| *TempStr = 0; |
| Length = 0; |
| } |
| else if (Precision > 0 && Precision < Length - 1) |
| { |
| Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, |
| Precision, TempStr, Length, |
| 0, 0); |
| if (!Length) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", |
| GetLastError()); |
| InternalFree(TempStr); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| TempStr[Length] = 0; |
| Length = Precision; |
| } |
| /* copy everything */ |
| else |
| { |
| wctombResult = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, |
| TempStr, Length, 0, 0); |
| if (!wctombResult) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", |
| GetLastError()); |
| InternalFree(TempStr); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| --Length; /* exclude null char */ |
| } |
| |
| /* do the padding (if needed)*/ |
| paddingReturnValue = |
| Internal_AddPaddingVfprintf(pthrCurrent, stream, TempStr, |
| Width - Length, Flags); |
| if (-1 == paddingReturnValue) |
| { |
| ERROR("Internal_AddPaddingVfprintf failed\n"); |
| InternalFree(TempStr); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| written += paddingReturnValue; |
| |
| InternalFree(TempStr); |
| } |
| else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR) |
| { |
| CHAR TempBuffer[5]; |
| if (WIDTH_STAR == Width || |
| WIDTH_INVALID == Width) |
| { |
| /* ignore (because it's a char), and remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| if (PRECISION_STAR == Precision || |
| PRECISION_INVALID == Precision) |
| { |
| /* ignore (because it's a char), and remove arg */ |
| TempInt = va_arg(ap, INT); /* value not used */ |
| } |
| |
| TempWChar = va_arg(ap, int); |
| Length = WideCharToMultiByte(CP_ACP, 0, &TempWChar, 1, |
| TempBuffer, sizeof(TempBuffer), |
| 0, 0); |
| if (!Length) |
| { |
| ASSERT("WideCharToMultiByte failed. Error is %d\n", |
| GetLastError()); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| TempBuffer[Length] = 0; |
| |
| /* do the padding (if needed)*/ |
| paddingReturnValue = |
| Internal_AddPaddingVfprintf(pthrCurrent, stream, TempBuffer, |
| Width - Length, Flags); |
| if (-1 == paddingReturnValue) |
| { |
| ERROR("Internal_AddPaddingVfprintf failed\n"); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| written += paddingReturnValue; |
| |
| } |
| /* this places the number of bytes written to the buffer in the |
| next arg */ |
| else if (Type == PFF_TYPE_N) |
| { |
| if (WIDTH_STAR == Width) |
| { |
| Width = va_arg(ap, INT); |
| } |
| if (PRECISION_STAR == Precision) |
| { |
| Precision = va_arg(ap, INT); |
| } |
| |
| if (Prefix == PFF_PREFIX_SHORT) |
| { |
| *(va_arg(ap, short *)) = written; |
| } |
| else |
| { |
| *(va_arg(ap, LPLONG)) = written; |
| } |
| } |
| else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0) |
| { |
| // Some versions of fprintf don't support 0-padded chars, |
| // so we handle them here. |
| char ch[2]; |
| |
| ch[0] = (char) va_arg(ap, int); |
| ch[1] = '\0'; |
| Length = 1; |
| paddingReturnValue = Internal_AddPaddingVfprintf( |
| pthrCurrent, |
| stream, |
| ch, |
| Width - Length, |
| Flags); |
| if (-1 == paddingReturnValue) |
| { |
| ERROR("Internal_AddPaddingVfprintf failed\n"); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| written += paddingReturnValue; |
| } |
| else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0) |
| { |
| // Some versions of fprintf don't support 0-padded strings, |
| // so we handle them here. |
| char *tempStr; |
| |
| tempStr = va_arg(ap, char *); |
| Length = strlen(tempStr); |
| paddingReturnValue = Internal_AddPaddingVfprintf( |
| pthrCurrent, |
| stream, |
| tempStr, |
| Width - Length, |
| Flags); |
| if (-1 == paddingReturnValue) |
| { |
| ERROR("Internal_AddPaddingVfprintf failed\n"); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| written += paddingReturnValue; |
| } |
| else |
| { |
| // Types that fprintf can handle. |
| TempInt = 0; |
| |
| // %h (short) doesn't seem to be handled properly by local sprintf, |
| // so we do the truncation ourselves for some cases. |
| if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT) |
| { |
| // Convert from pointer -> int -> short to avoid warnings. |
| long trunc1; |
| short trunc2; |
| |
| trunc1 = va_arg(ap, LONG); |
| trunc2 = (short)trunc1; |
| trunc1 = trunc2; |
| |
| TempInt = fprintf(stream->bsdFilePtr, TempBuff, trunc1); |
| } |
| else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT) |
| { |
| // Convert explicitly from int to short to get |
| // correct sign extension for shorts on all systems. |
| int n; |
| short s; |
| |
| n = va_arg(ap, int); |
| s = (short) n; |
| |
| TempInt = fprintf( stream->bsdFilePtr, TempBuff, s); |
| } |
| else |
| { |
| va_list apcopy; |
| va_copy(apcopy, ap); |
| TempInt = vfprintf(stream->bsdFilePtr, TempBuff, apcopy); |
| va_end(apcopy); |
| PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix); |
| } |
| |
| if (-1 == TempInt) |
| { |
| ERROR("vfprintf returned an error\n"); |
| } |
| else |
| { |
| written += TempInt; |
| } |
| } |
| } |
| else |
| { |
| |
| #if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL |
| clearerr (stream->bsdFilePtr); |
| #endif |
| |
| InternalFwrite(Fmt++, 1, 1, stream->bsdFilePtr, &stream->PALferrorCode); /* copy regular chars into buffer */ |
| if (stream->PALferrorCode == PAL_FILE_ERROR) |
| { |
| ERROR("fwrite() failed with errno == %d\n", errno); |
| PERF_EXIT(vfprintf); |
| va_end(ap); |
| return -1; |
| } |
| ++written; |
| } |
| } |
| |
| va_end(ap); |
| |
| PERF_EXIT(vfprintf); |
| return written; |
| } |