mirror of
https://github.com/SSCLI/sscli_20021101
synced 2026-06-08 12:28:57 +00:00
9fa3874800
Moved the original file to the archive subfolder.
3471 lines
98 KiB
C
3471 lines
98 KiB
C
/*++
|
|
|
|
|
|
Copyright (c) 2002 Microsoft Corporation. All rights reserved.
|
|
|
|
The use and distribution terms for this software are contained in the file
|
|
named license.txt, which can be found in the root of this distribution.
|
|
By using this software in any fashion, you are agreeing to be bound by the
|
|
terms of this license.
|
|
|
|
You must not remove this notice, or any other, from this software.
|
|
|
|
|
|
Module Name:
|
|
|
|
printf.c
|
|
|
|
Abstract:
|
|
|
|
Implementation of the printf family functions.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "pal/palinternal.h"
|
|
#include "pal/dbgmsg.h"
|
|
#include "pal/cruntime.h"
|
|
|
|
/* <stdarg.h> needs to be included after "palinternal.h" to avoid name
|
|
collision for va_start and va_end */
|
|
#include <stdarg.h>
|
|
#include <errno.h>
|
|
|
|
|
|
SET_DEFAULT_DEBUG_CHANNEL(CRT);
|
|
|
|
#if SSCANF_SUPPORT_ll
|
|
const static char *scanf_longlongfmt = "ll";
|
|
#else
|
|
const static char *scanf_longlongfmt = "q";
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
Internal_Convertfwrite
|
|
This function is a wrapper around fwrite for cases where the buffer has
|
|
to be converted from WideChar to MultiByte
|
|
*******************************************************************************/
|
|
|
|
static size_t Internal_Convertfwrite(const void *buffer, size_t size, size_t count , FILE *stream,BOOL convert)
|
|
{
|
|
int ret;
|
|
|
|
if(convert)
|
|
{
|
|
int nsize;
|
|
LPSTR newBuff = 0;
|
|
nsize = WideCharToMultiByte(CP_ACP, 0,buffer, count, 0, 0, 0, 0);
|
|
if (!nsize)
|
|
{
|
|
ASSERT("WideCharToMultiByte failed. Error is %d\n",
|
|
GetLastError());
|
|
return -1;
|
|
}
|
|
newBuff = (LPSTR) malloc(nsize);
|
|
if (!newBuff)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return -1;
|
|
}
|
|
nsize = WideCharToMultiByte(CP_ACP, 0, buffer, count,
|
|
newBuff, nsize, 0, 0);
|
|
if (!nsize)
|
|
{
|
|
ASSERT("WideCharToMultiByte failed. Error is %d\n",
|
|
GetLastError());
|
|
free(newBuff);
|
|
return -1;
|
|
}
|
|
ret = fwrite(newBuff,1,count,stream);
|
|
free(newBuff);
|
|
}
|
|
else
|
|
{
|
|
ret = fwrite(buffer,size,count,stream);
|
|
}
|
|
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
|
|
*******************************************************************************/
|
|
static BOOL Internal_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags,
|
|
LPINT Width, LPINT Precision,
|
|
LPINT Prefix, LPINT Type)
|
|
{
|
|
BOOL Result = FALSE;
|
|
LPSTR TempStr;
|
|
LPSTR TempStrPtr;
|
|
|
|
*Width = -1;
|
|
*Precision = -1;
|
|
*Flags = 0;
|
|
*Prefix = -1;
|
|
*Type = -1;
|
|
|
|
if (*Fmt && **Fmt == '%')
|
|
{
|
|
*Out++ = *(*Fmt)++;
|
|
}
|
|
else
|
|
{
|
|
return Result;
|
|
}
|
|
|
|
/* we'll never need a temp string longer than the original */
|
|
TempStrPtr = TempStr = (LPSTR) malloc(strlen(*Fmt)+1);
|
|
if (!TempStr)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
/* 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 = atol(TempStr);
|
|
}
|
|
|
|
/* 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 = atol(TempStr);
|
|
}
|
|
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_STAR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*Precision = PRECISION_DOT;
|
|
}
|
|
}
|
|
|
|
/* grab width specifier */
|
|
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)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* grab prefix of 'I64' for __int64 */
|
|
if ((*Fmt)[0] == 'I' && (*Fmt)[1] == '6' && (*Fmt)[2] == '4')
|
|
{
|
|
/* convert to 'll' so BSD's snprintf can handle it */
|
|
*Fmt += 3;
|
|
*Prefix = PFF_PREFIX_LONGLONG;
|
|
}
|
|
/* 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')
|
|
{
|
|
*Prefix = PFF_PREFIX_LONG;
|
|
++(*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 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)++;
|
|
*Out++ = '.';
|
|
if (*Prefix == PFF_PREFIX_LONGLONG)
|
|
{
|
|
/* native *printf does not support %I64p
|
|
(actually %llp), so we need to cheat a little bit */
|
|
*Out++ = '1';
|
|
*Out++ = '6';
|
|
*Out++ = 'l';
|
|
*Out++ = 'l';
|
|
}
|
|
else
|
|
{
|
|
*Out++ = '8';
|
|
}
|
|
*Out++ = 'X';
|
|
Result = TRUE;
|
|
}
|
|
|
|
*Out = 0; /* end the string */
|
|
free(TempStr);
|
|
return Result;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
Internal_ExtractFormatW
|
|
|
|
-- see Internal_ExtractFormatA above
|
|
*******************************************************************************/
|
|
static BOOL Internal_ExtractFormatW(LPCWSTR *Fmt, LPSTR Out, LPINT Flags,
|
|
LPINT Width, LPINT Precision,
|
|
LPINT Prefix, LPINT Type)
|
|
{
|
|
BOOL Result = FALSE;
|
|
LPSTR TempStr;
|
|
LPSTR TempStrPtr;
|
|
|
|
*Width = -1;
|
|
*Precision = -1;
|
|
*Flags = 0;
|
|
*Prefix = -1;
|
|
*Type = -1;
|
|
|
|
if (*Fmt && **Fmt == '%')
|
|
{
|
|
*Out++ = (CHAR) *(*Fmt)++;
|
|
}
|
|
else
|
|
{
|
|
return Result;
|
|
}
|
|
|
|
/* we'll never need a temp string longer than the original */
|
|
TempStrPtr = TempStr = (LPSTR) malloc(PAL_wcslen(*Fmt)+1);
|
|
if (!TempStr)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
/* 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 = atol(TempStr);
|
|
}
|
|
|
|
/* 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 = atol(TempStr);
|
|
}
|
|
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_STAR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*Precision = PRECISION_DOT;
|
|
}
|
|
}
|
|
|
|
/* grab prefix of 'I64' for __int64 */
|
|
if ((*Fmt)[0] == 'I' && (*Fmt)[1] == '6' && (*Fmt)[2] == '4')
|
|
{
|
|
/* convert to 'll' so BSD's snprintf can handle it */
|
|
*Fmt += 3;
|
|
*Prefix = PFF_PREFIX_LONGLONG;
|
|
}
|
|
/* grab a prefix of 'h' */
|
|
else if (**Fmt == 'h')
|
|
{
|
|
*Prefix = PFF_PREFIX_SHORT;
|
|
++(*Fmt);
|
|
}
|
|
else if (**Fmt == 'l' || **Fmt == 'w')
|
|
{
|
|
*Prefix = PFF_PREFIX_LONG_W;
|
|
++(*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 || 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 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)++;
|
|
*Out++ = '.';
|
|
if (*Prefix == PFF_PREFIX_LONGLONG)
|
|
{
|
|
/* native *printf does not support %I64p
|
|
(actually %llp), so we need to cheat a little bit */
|
|
*Out++ = '1';
|
|
*Out++ = '6';
|
|
*Out++ = 'l';
|
|
*Out++ = 'l';
|
|
}
|
|
else
|
|
{
|
|
if (*Prefix == PFF_PREFIX_LONG_W)
|
|
{
|
|
*Prefix = PFF_PREFIX_LONG;
|
|
}
|
|
*Out++ = '8';
|
|
}
|
|
*Out++ = 'X';
|
|
|
|
Result = TRUE;
|
|
}
|
|
|
|
*Out = 0; /* end the string */
|
|
free(TempStr);
|
|
return Result;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
Internal_AddPaddingA
|
|
|
|
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_AddPaddingA(LPSTR *Out, INT Count, LPSTR In,
|
|
INT Padding, INT Flags)
|
|
{
|
|
LPSTR OutOriginal = *Out;
|
|
INT PaddingOriginal = Padding;
|
|
INT LengthInStr;
|
|
LengthInStr = strlen(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 */
|
|
{
|
|
strncpy(*Out, In, min(LengthInStr + 1, Count));
|
|
*Out += min(LengthInStr, Count);
|
|
}
|
|
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 */
|
|
{
|
|
strncpy(*Out, In,
|
|
min(LengthInStr + 1, Count - (*Out - OutOriginal)));
|
|
*Out += min(LengthInStr, Count - (*Out - OutOriginal));
|
|
}
|
|
|
|
if (LengthInStr + PaddingOriginal > Count)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
Internal_AddPaddingW
|
|
|
|
-- see Internal_AddPaddingA above
|
|
*******************************************************************************/
|
|
static 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 */
|
|
{
|
|
lstrcpynW(*Out, In, min(LengthInStr + 1, Count));
|
|
*Out += min(LengthInStr, Count);
|
|
}
|
|
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 */
|
|
{
|
|
lstrcpynW(*Out, In,
|
|
min(LengthInStr + 1, Count - (*Out - OutOriginal)));
|
|
*Out += min(LengthInStr, Count - (*Out - OutOriginal));
|
|
}
|
|
|
|
if (LengthInStr + PaddingOriginal > Count)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
PAL_printf_arg_remover
|
|
|
|
Parameters:
|
|
ap
|
|
- pointer to the va_list from which to remove arguments
|
|
Precision
|
|
- the precision of the current format option
|
|
Type
|
|
- the type of the argument for the current format option
|
|
Prefix
|
|
- the prefix for the current format option
|
|
*******************************************************************************/
|
|
void PAL_printf_arg_remover(va_list *ap, INT Precision, INT Type, INT Prefix)
|
|
{
|
|
/* remove arg and precision if needed */
|
|
if (PRECISION_STAR == Precision ||
|
|
PRECISION_INVALID == Precision)
|
|
{
|
|
(void)va_arg(*ap, LONG);
|
|
}
|
|
if (Type == PFF_TYPE_FLOAT)
|
|
{
|
|
(void)va_arg(*ap, double);
|
|
}
|
|
else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_LONGLONG)
|
|
{
|
|
(void)va_arg(*ap, INT64);
|
|
}
|
|
else
|
|
{
|
|
(void)va_arg(*ap, LONG);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
PAL_vsnprintf
|
|
|
|
Parameters:
|
|
Buffer
|
|
- out buffer
|
|
Count
|
|
- buffer size
|
|
Format
|
|
- format string
|
|
ap
|
|
- stdarg parameter list
|
|
*******************************************************************************/
|
|
static INT PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list ap)
|
|
{
|
|
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;
|
|
|
|
while (*Fmt)
|
|
{
|
|
if ((BufferPtr - Buffer) >= Count)
|
|
{
|
|
BufferRanOut = TRUE;
|
|
break;
|
|
}
|
|
else if(*Fmt == '%' &&
|
|
TRUE == Internal_ExtractFormatA(&Fmt, TempBuff, &Flags,
|
|
&Width, &Precision,
|
|
&Prefix, &Type))
|
|
{
|
|
if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
|
|
{
|
|
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());
|
|
return -1;
|
|
}
|
|
TempStr = (LPSTR) malloc(Length);
|
|
if (!TempStr)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
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());
|
|
free(TempStr);
|
|
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());
|
|
free(TempStr);
|
|
return -1;
|
|
}
|
|
--Length; /* exclude null char */
|
|
}
|
|
|
|
/* do the padding (if needed)*/
|
|
BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
|
|
Count - (BufferPtr - Buffer),
|
|
TempStr,
|
|
Width - Length,
|
|
Flags);
|
|
|
|
free(TempStr);
|
|
}
|
|
else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
|
|
{
|
|
CHAR TempBuffer[5];
|
|
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());
|
|
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 (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
|
|
{
|
|
TempInt = vsnprintf(BufferPtr, TempCount, TempBuff, ap);
|
|
PAL_printf_arg_remover(&ap, Precision, Type, Prefix);
|
|
}
|
|
|
|
if (TempInt > TempCount) /* buffer not long enough */
|
|
{
|
|
BufferPtr += TempCount;
|
|
BufferRanOut = TRUE;
|
|
}
|
|
else
|
|
{
|
|
BufferPtr += TempInt;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*BufferPtr++ = *Fmt++; /* copy regular chars into buffer */
|
|
}
|
|
}
|
|
|
|
if (Count > (BufferPtr - Buffer))
|
|
{
|
|
*BufferPtr = 0; /* end the string */
|
|
}
|
|
|
|
if (BufferRanOut)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
|
|
return BufferPtr - Buffer;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
PAL_wvsnprintf
|
|
|
|
-- see PAL_vsnprintf above
|
|
*******************************************************************************/
|
|
static INT PAL_wvsnprintf(LPWSTR Buffer, INT Count, LPCWSTR Format, va_list ap)
|
|
{
|
|
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 Length;
|
|
INT TempInt;
|
|
LPSTR TempNumberBuffer;
|
|
int mbtowcResult;
|
|
|
|
while (*Fmt)
|
|
{
|
|
if ((BufferPtr - Buffer) >= Count)
|
|
{
|
|
BufferRanOut = TRUE;
|
|
break;
|
|
}
|
|
else if(*Fmt == '%' &&
|
|
TRUE == Internal_ExtractFormatW(&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 (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) ||
|
|
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)malloc( (Length + 1 ) * sizeof( WCHAR ) );
|
|
if ( TempWStr )
|
|
{
|
|
needToFree = TRUE;
|
|
MultiByteToWideChar( CP_ACP, 0, s, -1,
|
|
TempWStr, Length );
|
|
}
|
|
else
|
|
{
|
|
ERROR( "malloc failed.\n" );
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT( "Unable to convert from multibyte "
|
|
" to wide char.\n" );
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
Length = PAL_wcslen(TempWStr);
|
|
WorkingWStr = (LPWSTR) malloc(sizeof(WCHAR) * (Length + 1));
|
|
if (!WorkingWStr)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
if (needToFree)
|
|
{
|
|
free(TempWStr);
|
|
}
|
|
return -1;
|
|
}
|
|
if (PRECISION_DOT == Precision)
|
|
{
|
|
// Copy nothing
|
|
*WorkingWStr = 0;
|
|
Length = 0;
|
|
}
|
|
else if (Precision > 0 && Precision < Length)
|
|
{
|
|
lstrcpynW(WorkingWStr, TempWStr, Precision+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)
|
|
{
|
|
free(TempWStr);
|
|
}
|
|
free(WorkingWStr);
|
|
}
|
|
else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
|
|
{
|
|
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 (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
|
|
{
|
|
TempInt = vsnprintf((LPSTR) BufferPtr, TempCount, TempBuff, ap);
|
|
PAL_printf_arg_remover(&ap, Precision, Type, Prefix);
|
|
}
|
|
|
|
if (TempInt == 0)
|
|
{
|
|
// The argument is "".
|
|
continue;
|
|
}
|
|
if (TempInt > TempCount) /* buffer not long enough */
|
|
{
|
|
TempNumberBuffer = (LPSTR) malloc(TempCount);
|
|
if (!TempNumberBuffer)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return -1;
|
|
}
|
|
strncpy(TempNumberBuffer, (LPSTR) BufferPtr, TempCount);
|
|
mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
|
|
TempNumberBuffer,
|
|
TempCount,
|
|
BufferPtr, TempCount);
|
|
if (!mbtowcResult)
|
|
{
|
|
ASSERT("MultiByteToWideChar failed. Error is %d\n",
|
|
GetLastError());
|
|
free(TempNumberBuffer);
|
|
return -1;
|
|
}
|
|
BufferPtr += TempCount;
|
|
BufferRanOut = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TempNumberBuffer = (LPSTR) malloc(TempInt);
|
|
if (!TempNumberBuffer)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return -1;
|
|
}
|
|
strncpy(TempNumberBuffer, (LPSTR) BufferPtr, TempInt);
|
|
mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
|
|
TempNumberBuffer,
|
|
TempInt,
|
|
BufferPtr, TempInt);
|
|
if (!mbtowcResult)
|
|
{
|
|
ASSERT("MultiByteToWideChar failed. Error is %d\n",
|
|
GetLastError());
|
|
free(TempNumberBuffer);
|
|
return -1;
|
|
}
|
|
BufferPtr += TempInt;
|
|
}
|
|
free(TempNumberBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*BufferPtr++ = *Fmt++; /* copy regular chars into buffer */
|
|
}
|
|
}
|
|
|
|
if (Count > (BufferPtr - Buffer))
|
|
{
|
|
*BufferPtr = 0; /* end the string */
|
|
}
|
|
|
|
if (BufferRanOut)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return BufferPtr - Buffer;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
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)
|
|
*******************************************************************************/
|
|
static INT Internal_AddPaddingVfprintf(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) malloc(Length+1);
|
|
if (!Out)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return -1;
|
|
}
|
|
OutOriginal = Out;
|
|
|
|
if (Flags & PFF_MINUS) /* pad on right */
|
|
{
|
|
strcpy(Out, In);
|
|
Out += LengthInStr;
|
|
}
|
|
if (Padding > 0)
|
|
{
|
|
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 */
|
|
{
|
|
strcpy(Out, In);
|
|
Out += LengthInStr;
|
|
}
|
|
|
|
Written = fwrite(OutOriginal, 1, Length, stream->bsdFilePtr );
|
|
if (-1 == Written)
|
|
{
|
|
ERROR("fwrite() failed with errno == %d\n", errno);
|
|
}
|
|
free(OutOriginal);
|
|
|
|
return Written;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
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)
|
|
{
|
|
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;
|
|
while (*Fmt)
|
|
{
|
|
if (*Fmt == '%' &&
|
|
TRUE == Internal_ExtractFormatA(&Fmt, TempBuff, &Flags,
|
|
&Width, &Precision,
|
|
&Prefix, &Type))
|
|
{
|
|
if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
|
|
{
|
|
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());
|
|
return -1;
|
|
}
|
|
TempStr = (LPSTR) malloc(Length);
|
|
if (!TempStr)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
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());
|
|
free(TempStr);
|
|
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());
|
|
free(TempStr);
|
|
return -1;
|
|
}
|
|
--Length; /* exclude null char */
|
|
}
|
|
|
|
/* do the padding (if needed)*/
|
|
paddingReturnValue =
|
|
Internal_AddPaddingVfprintf(stream, TempStr,
|
|
Width - Length, Flags);
|
|
if (-1 == paddingReturnValue)
|
|
{
|
|
ERROR("Internal_AddPaddingVfprintf failed\n");
|
|
free(TempStr);
|
|
return -1;
|
|
}
|
|
written += paddingReturnValue;
|
|
|
|
free(TempStr);
|
|
}
|
|
else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
|
|
{
|
|
CHAR TempBuffer[5];
|
|
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());
|
|
return -1;
|
|
}
|
|
TempBuffer[Length] = 0;
|
|
|
|
/* do the padding (if needed)*/
|
|
paddingReturnValue =
|
|
Internal_AddPaddingVfprintf(stream, TempBuffer,
|
|
Width - Length, Flags);
|
|
if (-1 == paddingReturnValue)
|
|
{
|
|
ERROR("Internal_AddPaddingVfprintf failed\n");
|
|
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 (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(stream,
|
|
ch,
|
|
Width - Length,
|
|
Flags);
|
|
if (-1 == paddingReturnValue)
|
|
{
|
|
ERROR("Internal_AddPaddingVfprintf failed\n");
|
|
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(stream,
|
|
tempStr,
|
|
Width - Length,
|
|
Flags);
|
|
if (-1 == paddingReturnValue)
|
|
{
|
|
ERROR("Internal_AddPaddingVfprintf failed\n");
|
|
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
|
|
{
|
|
TempInt = vfprintf( stream->bsdFilePtr, TempBuff, ap);
|
|
PAL_printf_arg_remover(&ap, Precision, Type, Prefix);
|
|
}
|
|
|
|
if (-1 == TempInt)
|
|
{
|
|
ERROR("vfprintf returned an error\n");
|
|
}
|
|
else
|
|
{
|
|
written += TempInt;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int ret;
|
|
|
|
ret = fwrite(Fmt++, 1, 1, stream->bsdFilePtr); /* copy regular chars into buffer */
|
|
if (-1 == ret)
|
|
{
|
|
ERROR("fwrite() failed with errno == %d\n", errno);
|
|
return -1;
|
|
}
|
|
++written;
|
|
}
|
|
}
|
|
|
|
return written;
|
|
}
|
|
|
|
/*++
|
|
Function:
|
|
PAL_printf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_printf(
|
|
const char *format,
|
|
...)
|
|
{
|
|
LONG Length;
|
|
va_list ap;
|
|
|
|
ENTRY("PAL_printf (format=%p (%s))\n", format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_vprintf(format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("PAL_printf returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
PAL_fprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_fprintf(PAL_FILE *stream,const char *format,...)
|
|
{
|
|
LONG Length = 0;
|
|
va_list ap;
|
|
|
|
ENTRY("PAL_fprintf(stream=%p,format=%p (%s))\n",stream, format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_vfprintf( stream, format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("PAL_fprintf returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
PAL_vprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_vprintf(
|
|
const char *format,
|
|
va_list ap)
|
|
{
|
|
LONG Length;
|
|
|
|
ENTRY("PAL_vprintf (format=%p (%s))\n", format, format);
|
|
|
|
Length = PAL_vfprintf( PAL_get_stdout(), format, ap);
|
|
|
|
LOGEXIT("PAL_vprintf returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
wsprintfA
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
PALAPIV
|
|
wsprintfA(
|
|
OUT LPSTR buffer,
|
|
IN LPCSTR format,
|
|
...)
|
|
{
|
|
LONG Length;
|
|
va_list ap;
|
|
|
|
ENTRY("wsprintfA (buffer=%p, format=%p (%s))\n", buffer, format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_vsnprintf(buffer, 1024, format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("wsprintfA returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
/*++
|
|
Function:
|
|
wsprintfW
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
PALAPIV
|
|
wsprintfW(
|
|
OUT LPWSTR buffer,
|
|
IN LPCWSTR format,
|
|
...)
|
|
{
|
|
LONG Length;
|
|
va_list ap;
|
|
|
|
ENTRY("wsprintfW (buffer=%p, format=%p (%S))\n", buffer, format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_wvsnprintf(buffer, 1024, format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("wsprintfW returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
_snprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
_snprintf(
|
|
char *buffer,
|
|
size_t count,
|
|
const char *format,
|
|
...)
|
|
{
|
|
LONG Length;
|
|
va_list ap;
|
|
|
|
ENTRY("_snprintf (buffer=%p, count=%lu, format=%p (%s))\n",
|
|
buffer, (unsigned long) count, format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_vsnprintf(buffer, count, format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("_snprintf returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
_snwprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
_snwprintf(
|
|
wchar_16 *buffer,
|
|
size_t count,
|
|
const wchar_16 *format,
|
|
...)
|
|
{
|
|
LONG Length;
|
|
va_list ap;
|
|
|
|
ENTRY("_snwprintf (buffer=%p, count=%lu, format=%p (%S))\n",
|
|
buffer, (unsigned long) count, format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_wvsnprintf(buffer, count, format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("_snwprintf returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
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(PAL_FILE *stream, LPWSTR In,
|
|
INT Padding, INT Flags,BOOL convert)
|
|
{
|
|
LPWSTR Out;
|
|
LPWSTR OutOriginal;
|
|
INT LengthInStr;
|
|
INT Length;
|
|
INT Written;
|
|
|
|
LengthInStr = PAL_wcslen(In);
|
|
Length = LengthInStr;
|
|
|
|
|
|
if (Padding > 0)
|
|
{
|
|
Length += Padding;
|
|
}
|
|
Out = (LPWSTR) malloc((Length+1) * sizeof(wchar_16));
|
|
if (!Out)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return -1;
|
|
}
|
|
OutOriginal = Out;
|
|
|
|
if (Flags & PFF_MINUS) /* pad on right */
|
|
{
|
|
lstrcpyW(Out, In);
|
|
Out += LengthInStr;
|
|
}
|
|
if (Padding > 0)
|
|
{
|
|
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 */
|
|
{
|
|
lstrcpyW(Out, In);
|
|
Out += LengthInStr;
|
|
}
|
|
|
|
Written = Internal_Convertfwrite(OutOriginal, sizeof(wchar_16), Length,
|
|
(FILE*)(stream->bsdFilePtr),
|
|
convert);
|
|
|
|
if (-1 == Written)
|
|
{
|
|
ERROR("fwrite() failed with errno == %d\n", errno);
|
|
}
|
|
free(OutOriginal);
|
|
|
|
return Written;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
fwprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_fwprintf(
|
|
PAL_FILE *stream,
|
|
const wchar_16 *format,
|
|
...)
|
|
{
|
|
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 Length=0;
|
|
INT TempInt;
|
|
BOOL WStrWasMalloced = FALSE;
|
|
int mbtowcResult;
|
|
int written=0;
|
|
int paddingReturnValue;
|
|
va_list ap;
|
|
int ret;
|
|
|
|
/* 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;
|
|
|
|
ENTRY("fwprintf (stream=%p, format=%p (%S))\n",
|
|
stream, format, format);
|
|
|
|
va_start(ap, format);
|
|
|
|
while (*Fmt)
|
|
{
|
|
if(*Fmt == '%' &&
|
|
TRUE == Internal_ExtractFormatW(&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 (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)malloc( (Length) * sizeof( WCHAR ) );
|
|
if ( TempWStr )
|
|
{
|
|
WStrWasMalloced = TRUE;
|
|
MultiByteToWideChar( CP_ACP, 0, s, -1,
|
|
TempWStr, Length );
|
|
}
|
|
else
|
|
{
|
|
ERROR( "malloc failed.\n" );
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT( "Unable to convert from multibyte "
|
|
" to wide char.\n" );
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
Length = PAL_wcslen(TempWStr);
|
|
WorkingWStr = (LPWSTR) malloc(sizeof(WCHAR) * (Length + 1));
|
|
if (!WorkingWStr)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
if (WStrWasMalloced)
|
|
{
|
|
free(TempWStr);
|
|
}
|
|
return -1;
|
|
}
|
|
if (PRECISION_DOT == Precision)
|
|
{
|
|
/* copy nothing */
|
|
*WorkingWStr = 0;
|
|
Length = 0;
|
|
}
|
|
else if (Precision > 0 && Precision < Length)
|
|
{
|
|
lstrcpynW(WorkingWStr, TempWStr, Precision+1);
|
|
Length = Precision;
|
|
}
|
|
/* copy everything */
|
|
else
|
|
{
|
|
PAL_wcscpy(WorkingWStr, TempWStr);
|
|
}
|
|
|
|
|
|
/* do the padding (if needed)*/
|
|
paddingReturnValue =
|
|
Internal_AddPaddingVfwprintf( stream, WorkingWStr,
|
|
Width - Length,
|
|
Flags,textMode);
|
|
|
|
if (paddingReturnValue == -1)
|
|
{
|
|
ERROR("Internal_AddPaddingVfwprintf failed\n");
|
|
if (WStrWasMalloced)
|
|
{
|
|
free(TempWStr);
|
|
}
|
|
free(WorkingWStr);
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
return (-1);
|
|
}
|
|
written += paddingReturnValue;
|
|
|
|
free(WorkingWStr);
|
|
if (WStrWasMalloced)
|
|
{
|
|
free(TempWStr);
|
|
}
|
|
}
|
|
else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
|
|
{
|
|
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(stream, TempWChar,
|
|
Width - 1,
|
|
Flags,textMode);
|
|
if (paddingReturnValue == -1)
|
|
{
|
|
ERROR("Internal_AddPaddingVfwprintf failed\n");
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
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 (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 >= TEMP_COUNT)
|
|
{
|
|
if (NULL == (TempSprintfStrPtr = malloc(++TempInt)))
|
|
{
|
|
ERROR("malloc failed\n");
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
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 >= TEMP_COUNT)
|
|
{
|
|
if (NULL == (TempSprintfStrPtr = malloc(++TempInt)))
|
|
{
|
|
ERROR("malloc failed\n");
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return -1;
|
|
}
|
|
|
|
TempSprintfStr = TempSprintfStrPtr;
|
|
snprintf(TempSprintfStr, TempInt, TempBuff, s);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TempInt = vsnprintf(TempSprintfStr, TEMP_COUNT, TempBuff, ap);
|
|
|
|
if (TempInt >= TEMP_COUNT)
|
|
{
|
|
if (NULL == (TempSprintfStrPtr = malloc(++TempInt)))
|
|
{
|
|
ERROR("malloc failed\n");
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return -1;
|
|
}
|
|
|
|
TempSprintfStr = TempSprintfStrPtr;
|
|
vsnprintf(TempSprintfStr, TempInt, TempBuff, ap);
|
|
}
|
|
|
|
PAL_printf_arg_remover(&ap, Precision, Type, Prefix);
|
|
}
|
|
|
|
mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
|
|
TempSprintfStr, -1,
|
|
NULL, 0);
|
|
|
|
if (mbtowcResult == 0)
|
|
{
|
|
ERROR("WideCharToMultiByte failed\n");
|
|
if(TempSprintfStrPtr)
|
|
{
|
|
free(TempSprintfStrPtr);
|
|
}
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
return -1;
|
|
}
|
|
|
|
TempWideBuffer = (LPWSTR) malloc(mbtowcResult*sizeof(WCHAR));
|
|
if (!TempWideBuffer)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
if(TempSprintfStrPtr)
|
|
{
|
|
free(TempSprintfStrPtr);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, TempSprintfStr, -1,
|
|
TempWideBuffer, mbtowcResult);
|
|
|
|
ret = Internal_Convertfwrite(TempWideBuffer, sizeof(wchar_16),
|
|
mbtowcResult-1,
|
|
(FILE*)stream->bsdFilePtr,
|
|
textMode);
|
|
|
|
if (-1 == ret)
|
|
{
|
|
ERROR("fwrite() failed with errno == %d (%s)\n", errno, strerror(errno));
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
free(TempWideBuffer);
|
|
if(TempSprintfStrPtr)
|
|
{
|
|
free(TempSprintfStrPtr);
|
|
}
|
|
return -1;
|
|
}
|
|
if(TempSprintfStrPtr)
|
|
{
|
|
free(TempSprintfStrPtr);
|
|
}
|
|
free(TempWideBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int ret;
|
|
ret = Internal_Convertfwrite(Fmt++, sizeof(wchar_16), 1,
|
|
(FILE*)stream->bsdFilePtr,
|
|
textMode); /* copy regular chars into buffer */
|
|
if (-1 == ret)
|
|
{
|
|
ERROR("fwrite() failed with errno == %d\n", errno);
|
|
LOGEXIT("fwprintf returns int -1\n");
|
|
return -1;
|
|
}
|
|
++written;
|
|
}
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
LOGEXIT("fwprintf returns int %d\n", written);
|
|
return (written);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
Internal_ScanfExtractFormatA
|
|
|
|
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
|
|
Store
|
|
- boolean value representing whether to store the type to be parsed
|
|
- '*' flag
|
|
Width
|
|
- will contain the width specified by the format string
|
|
- -1 if none given
|
|
Prefix
|
|
- an enumeration of the type prefix
|
|
Type
|
|
- an enumeration of the value type to be parsed
|
|
|
|
Notes:
|
|
- I'm also handling the undocumented %ws, %wc, %w...
|
|
*******************************************************************************/
|
|
static BOOL Internal_ScanfExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPBOOL Store,
|
|
LPINT Width, LPINT Prefix, LPINT Type)
|
|
{
|
|
BOOL Result = FALSE;
|
|
LPSTR TempStr;
|
|
LPSTR TempStrPtr;
|
|
|
|
*Width = -1;
|
|
*Store = TRUE;
|
|
*Prefix = -1;
|
|
*Type = -1;
|
|
|
|
if (*Fmt && **Fmt == '%')
|
|
{
|
|
*Out++ = *(*Fmt)++;
|
|
}
|
|
else
|
|
{
|
|
return Result;
|
|
}
|
|
|
|
/* we'll never need a temp string longer than the original */
|
|
TempStrPtr = TempStr = (LPSTR) malloc(strlen(*Fmt)+1);
|
|
if (!TempStr)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
/* parse '*' flag which means don't store */
|
|
if (**Fmt == '*')
|
|
{
|
|
*Store = FALSE;
|
|
*Out++ = *(*Fmt)++;
|
|
}
|
|
|
|
/* grab width specifier */
|
|
if (isdigit((unsigned char) **Fmt))
|
|
{
|
|
TempStrPtr = TempStr;
|
|
while (isdigit((unsigned char) **Fmt))
|
|
{
|
|
*TempStrPtr++ = **Fmt;
|
|
*Out++ = *(*Fmt)++;
|
|
}
|
|
*TempStrPtr = 0; /* end string */
|
|
*Width = atol(TempStr);
|
|
}
|
|
|
|
/* grab prefix of 'I64' for __int64 */
|
|
if ((*Fmt)[0] == 'I' && (*Fmt)[1] == '6' && (*Fmt)[2] == '4')
|
|
{
|
|
/* convert to 'q'/'ll' so BSD's sscanf can handle it */
|
|
*Fmt += 3;
|
|
*Prefix = SCANF_PREFIX_LONGLONG;
|
|
}
|
|
/* grab a prefix of 'h' */
|
|
else if (**Fmt == 'h')
|
|
{
|
|
*Prefix = SCANF_PREFIX_SHORT;
|
|
++(*Fmt);
|
|
}
|
|
/* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */
|
|
else if (**Fmt == 'l' || **Fmt == 'w')
|
|
{
|
|
*Prefix = SCANF_PREFIX_LONG;
|
|
++(*Fmt);
|
|
}
|
|
else if (**Fmt == 'L')
|
|
{
|
|
/* a prefix of 'L' seems to be ignored */
|
|
++(*Fmt);
|
|
}
|
|
|
|
/* grab type 'c' */
|
|
if (**Fmt == 'c' || **Fmt == 'C')
|
|
{
|
|
*Type = SCANF_TYPE_CHAR;
|
|
if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 'C')
|
|
{
|
|
*Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
|
|
}
|
|
if (*Prefix == SCANF_PREFIX_LONG)
|
|
{
|
|
*Out++ = 'l';
|
|
}
|
|
*Out++ = 'c';
|
|
++(*Fmt);
|
|
Result = TRUE;
|
|
}
|
|
/* grab type 's' */
|
|
else if (**Fmt == 's' || **Fmt == 'S')
|
|
{
|
|
*Type = SCANF_TYPE_STRING;
|
|
if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 'S')
|
|
{
|
|
*Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
|
|
}
|
|
if (*Prefix == SCANF_PREFIX_LONG)
|
|
{
|
|
*Out++ = 'l';
|
|
}
|
|
*Out++ = 's';
|
|
++(*Fmt);
|
|
Result = TRUE;
|
|
}
|
|
/* grab int types types */
|
|
else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' ||
|
|
**Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X' ||
|
|
**Fmt == 'p')
|
|
{
|
|
*Type = SCANF_TYPE_INT;
|
|
if (*Prefix == SCANF_PREFIX_SHORT)
|
|
{
|
|
*Out++ = 'h';
|
|
}
|
|
else if (*Prefix == SCANF_PREFIX_LONG)
|
|
{
|
|
*Out++ = 'l';
|
|
}
|
|
else if (*Prefix == SCANF_PREFIX_LONGLONG)
|
|
{
|
|
strcpy(Out, scanf_longlongfmt);
|
|
Out += strlen(scanf_longlongfmt);
|
|
}
|
|
*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 = SCANF_TYPE_FLOAT;
|
|
/* this gets rid of %E/%G since they're they're the
|
|
same when scanning */
|
|
*Out++ = tolower( *(*Fmt)++ );
|
|
Result = TRUE;
|
|
}
|
|
else if (**Fmt == 'n')
|
|
{
|
|
if (*Prefix == SCANF_PREFIX_SHORT)
|
|
{
|
|
*Out++ = 'h';
|
|
}
|
|
*Out++ = *(*Fmt)++;
|
|
*Type = SCANF_TYPE_N;
|
|
Result = TRUE;
|
|
}
|
|
else if (**Fmt == '[')
|
|
{
|
|
/* There is a small compatibility problem in the handling of the []
|
|
option in FreeBSD vs. Windows. In Windows, you can have [z-a]
|
|
as well as [a-z]. In FreeBSD, [z-a] fails. So, we need to
|
|
reverse the instances of z-a to a-z (and [m-e] to [e-m], etc). */
|
|
|
|
/* step 1 : copy the leading [ */
|
|
*Out++ = '[';
|
|
(*Fmt)++;
|
|
|
|
/* step 2 : copy a leading ^, if present */
|
|
if( '^' == **Fmt )
|
|
{
|
|
*Out++ = '^';
|
|
(*Fmt)++;
|
|
}
|
|
|
|
/* step 3 : copy a leading ], if present; a ] immediately after the
|
|
leading [ (or [^) does *not* end the sequence, it is part of the
|
|
characters to match */
|
|
if( ']' == **Fmt )
|
|
{
|
|
*Out++ = ']';
|
|
(*Fmt)++;
|
|
}
|
|
|
|
/* step 4 : if the next character is already a '-', it's not part of an
|
|
interval specifier, so just copy it */
|
|
if('-' == **Fmt )
|
|
{
|
|
*Out++ = '-';
|
|
(*Fmt)++;
|
|
}
|
|
|
|
/* ok then, process the rest of it */
|
|
while( '\0' != **Fmt )
|
|
{
|
|
if(']' == **Fmt)
|
|
{
|
|
/* ']' marks end of the format specifier; we're done */
|
|
*Out++ = ']';
|
|
(*Fmt)++;
|
|
break;
|
|
}
|
|
if('-' == **Fmt)
|
|
{
|
|
if( ']' == (*Fmt)[1] )
|
|
{
|
|
/* got a '-', next character is the terminating ']';
|
|
copy '-' literally */
|
|
*Out++ = '-';
|
|
(*Fmt)++;
|
|
}
|
|
else
|
|
{
|
|
/* got a '-' indicating an interval specifier */
|
|
unsigned char prev, next;
|
|
|
|
/* get the interval boundaries */
|
|
prev = (*Fmt)[-1];
|
|
next = (*Fmt)[1];
|
|
|
|
/* if boundaries were inverted, replace the already-copied
|
|
low boundary by the 'real' low boundary */
|
|
if( prev > next )
|
|
{
|
|
Out[-1] = next;
|
|
|
|
/* ...and save the 'real' upper boundary, which will be
|
|
copied to 'Out' below */
|
|
next = prev;
|
|
}
|
|
|
|
*Out++ = '-';
|
|
*Out++ = next;
|
|
|
|
/* skip over the '-' and the next character, which we
|
|
already copied */
|
|
(*Fmt)+=2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* plain character; just copy it */
|
|
*Out++ = **Fmt;
|
|
(*Fmt)++;
|
|
}
|
|
}
|
|
|
|
*Type = SCANF_TYPE_BRACKETS;
|
|
Result = TRUE;
|
|
}
|
|
else if (**Fmt == ' ')
|
|
{
|
|
*Type = SCANF_TYPE_SPACE;
|
|
}
|
|
|
|
/* add %n so we know how far to increment the pointer */
|
|
*Out++ = '%';
|
|
*Out++ = 'n';
|
|
|
|
*Out = 0; /* end the string */
|
|
free(TempStr);
|
|
return Result;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
Internal_ScanfExtractFormatW
|
|
|
|
-- see Internal_ScanfExtractFormatA above
|
|
*******************************************************************************/
|
|
static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, LPBOOL Store,
|
|
LPINT Width, LPINT Prefix, LPINT Type)
|
|
{
|
|
BOOL Result = FALSE;
|
|
LPSTR TempStr;
|
|
LPSTR TempStrPtr;
|
|
|
|
*Width = -1;
|
|
*Store = TRUE;
|
|
*Prefix = -1;
|
|
*Type = -1;
|
|
|
|
if (*Fmt && **Fmt == '%')
|
|
{
|
|
*Out++ = *(*Fmt)++;
|
|
}
|
|
else
|
|
{
|
|
return Result;
|
|
}
|
|
|
|
/* we'll never need a temp string longer than the original */
|
|
TempStrPtr = TempStr = (LPSTR) malloc(PAL_wcslen(*Fmt)+1);
|
|
if (!TempStr)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
/* parse '*' flag which means don't store */
|
|
if (**Fmt == '*')
|
|
{
|
|
*Store = FALSE;
|
|
*Out++ = *(*Fmt)++;
|
|
}
|
|
|
|
/* grab width specifier */
|
|
if (isdigit(**Fmt))
|
|
{
|
|
TempStrPtr = TempStr;
|
|
while (isdigit(**Fmt))
|
|
{
|
|
*TempStrPtr++ = **Fmt;
|
|
*Out++ = *(*Fmt)++;
|
|
}
|
|
*TempStrPtr = 0; /* end string */
|
|
*Width = atol(TempStr);
|
|
}
|
|
|
|
/* grab prefix of 'I64' for __int64 */
|
|
if ((*Fmt)[0] == 'I' && (*Fmt)[1] == '6' && (*Fmt)[2] == '4')
|
|
{
|
|
/* convert to 'q'/'ll' so BSD's sscanf can handle it */
|
|
*Fmt += 3;
|
|
*Prefix = SCANF_PREFIX_LONGLONG;
|
|
}
|
|
/* grab a prefix of 'h' */
|
|
else if (**Fmt == 'h')
|
|
{
|
|
*Prefix = SCANF_PREFIX_SHORT;
|
|
++(*Fmt);
|
|
}
|
|
/* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */
|
|
else if (**Fmt == 'l' || **Fmt == 'w')
|
|
{
|
|
*Prefix = SCANF_PREFIX_LONG;
|
|
++(*Fmt);
|
|
}
|
|
else if (**Fmt == 'L')
|
|
{
|
|
/* a prefix of 'L' seems to be ignored */
|
|
++(*Fmt);
|
|
}
|
|
|
|
/* grab type 'c' */
|
|
if (**Fmt == 'c' || **Fmt == 'C')
|
|
{
|
|
*Type = SCANF_TYPE_CHAR;
|
|
if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 'c')
|
|
{
|
|
*Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
|
|
}
|
|
if (*Prefix == SCANF_PREFIX_LONG)
|
|
{
|
|
*Out++ = 'l';
|
|
}
|
|
*Out++ = 'c';
|
|
++(*Fmt);
|
|
Result = TRUE;
|
|
}
|
|
/* grab type 's' */
|
|
else if (**Fmt == 's' || **Fmt == 'S')
|
|
{
|
|
*Type = SCANF_TYPE_STRING;
|
|
if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 's')
|
|
{
|
|
*Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
|
|
}
|
|
if (*Prefix == SCANF_PREFIX_LONG)
|
|
{
|
|
*Out++ = 'l';
|
|
}
|
|
*Out++ = 's';
|
|
++(*Fmt);
|
|
Result = TRUE;
|
|
}
|
|
/* grab int types types */
|
|
else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' ||
|
|
**Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X' ||
|
|
**Fmt == 'p')
|
|
{
|
|
*Type = SCANF_TYPE_INT;
|
|
if (*Prefix == SCANF_PREFIX_SHORT)
|
|
{
|
|
*Out++ = 'h';
|
|
}
|
|
else if (*Prefix == SCANF_PREFIX_LONG)
|
|
{
|
|
*Out++ = 'l';
|
|
}
|
|
else if (*Prefix == SCANF_PREFIX_LONGLONG)
|
|
{
|
|
strcpy(Out, scanf_longlongfmt);
|
|
Out += strlen(scanf_longlongfmt);
|
|
}
|
|
*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 = SCANF_TYPE_FLOAT;
|
|
/* this gets rid of %E/%G since they're they're the
|
|
same when scanning */
|
|
*Out++ = tolower( *(*Fmt)++ );
|
|
Result = TRUE;
|
|
}
|
|
else if (**Fmt == 'n')
|
|
{
|
|
if (*Prefix == SCANF_PREFIX_SHORT)
|
|
{
|
|
*Out++ = 'h';
|
|
}
|
|
*Out++ = *(*Fmt)++;
|
|
*Type = SCANF_TYPE_N;
|
|
Result = TRUE;
|
|
}
|
|
else if (**Fmt == '[')
|
|
{
|
|
/* There is a small compatibility problem in the handling of the []
|
|
option in FreeBSD vs. Windows. In Windows, you can have [z-a]
|
|
as well as [a-z]. In FreeBSD, [z-a] fails. So, we need to
|
|
reverse the instances of z-a to a-z (and [m-e] to [e-m], etc). */
|
|
|
|
/* step 1 : copy the leading [ */
|
|
*Out++ = '[';
|
|
(*Fmt)++;
|
|
|
|
/* step 2 : copy a leading ^, if present */
|
|
if( '^' == **Fmt )
|
|
{
|
|
*Out++ = '^';
|
|
(*Fmt)++;
|
|
}
|
|
|
|
/* step 3 : copy a leading ], if present; a ] immediately after the
|
|
leading [ (or [^) does *not* end the sequence, it is part of the
|
|
characters to match */
|
|
if( ']' == **Fmt )
|
|
{
|
|
*Out++ = ']';
|
|
(*Fmt)++;
|
|
}
|
|
|
|
/* step 4 : if the next character is already a '-', it's not part of an
|
|
interval specifier, so just copy it */
|
|
if('-' == **Fmt )
|
|
{
|
|
*Out++ = '-';
|
|
(*Fmt)++;
|
|
}
|
|
|
|
/* ok then, process the rest of it */
|
|
while( '\0' != **Fmt )
|
|
{
|
|
if(']' == **Fmt)
|
|
{
|
|
/* ']' marks end of the format specifier; we're done */
|
|
*Out++ = ']';
|
|
(*Fmt)++;
|
|
break;
|
|
}
|
|
if('-' == **Fmt)
|
|
{
|
|
if( ']' == (*Fmt)[1] )
|
|
{
|
|
/* got a '-', next character is the terminating ']';
|
|
copy '-' literally */
|
|
*Out++ = '-';
|
|
(*Fmt)++;
|
|
}
|
|
else
|
|
{
|
|
/* got a '-' indicating an interval specifier */
|
|
unsigned char prev, next;
|
|
|
|
/* get the interval boundaries */
|
|
prev = (*Fmt)[-1];
|
|
next = (*Fmt)[1];
|
|
|
|
/* if boundaries were inverted, replace the already-copied
|
|
low boundary by the 'real' low boundary */
|
|
if( prev > next )
|
|
{
|
|
Out[-1] = next;
|
|
|
|
/* ...and save the 'real' upper boundary, which will be
|
|
copied to 'Out' below */
|
|
next = prev;
|
|
}
|
|
|
|
*Out++ = '-';
|
|
*Out++ = next;
|
|
|
|
/* skip over the '-' and the next character, which we
|
|
already copied */
|
|
(*Fmt)+=2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* plain character; just copy it */
|
|
*Out++ = **Fmt;
|
|
(*Fmt)++;
|
|
}
|
|
}
|
|
|
|
*Type = SCANF_TYPE_BRACKETS;
|
|
Result = TRUE;
|
|
}
|
|
else if (**Fmt == ' ')
|
|
{
|
|
*Type = SCANF_TYPE_SPACE;
|
|
}
|
|
|
|
/* add %n so we know how far to increment the pointer */
|
|
*Out++ = '%';
|
|
*Out++ = 'n';
|
|
|
|
*Out = 0; /* end the string */
|
|
free(TempStr);
|
|
return Result;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
PAL_vsscanf
|
|
|
|
Parameters:
|
|
Buffer
|
|
- buffer to parse values from
|
|
Format
|
|
- format string
|
|
ap
|
|
- stdarg parameter list
|
|
*******************************************************************************/
|
|
int PAL_vsscanf(LPCSTR Buffer, LPCSTR Format, va_list ap)
|
|
{
|
|
INT Length = 0;
|
|
LPCSTR Buff = Buffer;
|
|
LPCSTR Fmt = Format;
|
|
CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
|
|
BOOL Store;
|
|
INT Width;
|
|
INT Prefix;
|
|
INT Type;
|
|
|
|
while (*Fmt)
|
|
{
|
|
if (!*Buff && Length == 0)
|
|
{
|
|
Length = EOF;
|
|
break;
|
|
}
|
|
/* remove any number of blanks */
|
|
else if (isspace((unsigned char) *Fmt))
|
|
{
|
|
while (isspace((unsigned char) *Buff))
|
|
{
|
|
++Buff;
|
|
}
|
|
++Fmt;
|
|
}
|
|
else if (*Fmt == '%' &&
|
|
Internal_ScanfExtractFormatA(&Fmt, TempBuff, &Store,
|
|
&Width, &Prefix, &Type))
|
|
{
|
|
if (Prefix == SCANF_PREFIX_LONG &&
|
|
(Type == SCANF_TYPE_STRING || Type == SCANF_TYPE_CHAR))
|
|
{
|
|
int len = 0;
|
|
int res;
|
|
WCHAR *charPtr = 0;
|
|
|
|
/* a single character */
|
|
if (Type == SCANF_TYPE_CHAR && Width == -1)
|
|
{
|
|
len = Width = 1;
|
|
}
|
|
|
|
/* calculate length of string to copy */
|
|
while (Buff[len] && !isspace((unsigned char) Buff[len]))
|
|
{
|
|
if (Width != -1 && len >= Width)
|
|
{
|
|
break;
|
|
}
|
|
++len;
|
|
}
|
|
|
|
if (Store)
|
|
{
|
|
charPtr = va_arg(ap, WCHAR *);
|
|
|
|
res = MultiByteToWideChar(CP_ACP, 0, Buff, len,
|
|
charPtr, len);
|
|
if (!res)
|
|
{
|
|
ASSERT("MultiByteToWideChar failed. Error is %d\n",
|
|
GetLastError());
|
|
return -1;
|
|
}
|
|
if (Type == SCANF_TYPE_STRING)
|
|
{
|
|
/* end string */
|
|
charPtr[res] = 0;
|
|
}
|
|
++Length;
|
|
}
|
|
Buff += len;
|
|
}
|
|
/* this places the number of bytes stored into the next arg */
|
|
else if (Type == SCANF_TYPE_N)
|
|
{
|
|
if (Prefix == SCANF_PREFIX_SHORT)
|
|
{
|
|
*(va_arg(ap, short *)) = Buff - Buffer;
|
|
}
|
|
else
|
|
{
|
|
*(va_arg(ap, LPLONG)) = Buff - Buffer;
|
|
}
|
|
}
|
|
/* types that sscanf can handle */
|
|
else
|
|
{
|
|
int ret;
|
|
int n;
|
|
if (Store)
|
|
{
|
|
LPVOID voidPtr;
|
|
voidPtr = va_arg(ap, LPVOID);
|
|
ret = sscanf(Buff, TempBuff, voidPtr, &n);
|
|
}
|
|
else
|
|
{
|
|
ret = sscanf(Buff, TempBuff, &n);
|
|
}
|
|
if (ret > 0)
|
|
{
|
|
Length += ret;
|
|
}
|
|
else
|
|
{
|
|
/* no match, break scan */
|
|
break;
|
|
}
|
|
Buff += n;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* grab, but not store */
|
|
if (*Fmt == *Buff && Type != SCANF_TYPE_SPACE)
|
|
{
|
|
++Fmt;
|
|
++Buff;
|
|
}
|
|
/* doesn't match, break scan */
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Length;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
Function:
|
|
PAL_wvsscanf
|
|
|
|
-- see PAL_vsscanf above
|
|
*******************************************************************************/
|
|
int PAL_wvsscanf(LPCWSTR Buffer, LPCWSTR Format, va_list ap)
|
|
{
|
|
INT Length = 0;
|
|
LPCWSTR Buff = Buffer;
|
|
LPCWSTR Fmt = Format;
|
|
CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
|
|
BOOL Store;
|
|
INT Width;
|
|
INT Prefix;
|
|
INT Type;
|
|
|
|
while (*Fmt)
|
|
{
|
|
if (!*Buff && Length == 0)
|
|
{
|
|
Length = EOF;
|
|
break;
|
|
}
|
|
/* remove any number of blanks */
|
|
else if (isspace(*Fmt))
|
|
{
|
|
while (isspace(*Buff))
|
|
{
|
|
++Buff;
|
|
}
|
|
++Fmt;
|
|
}
|
|
else if (*Fmt == '%' &&
|
|
Internal_ScanfExtractFormatW(&Fmt, TempBuff, &Store,
|
|
&Width, &Prefix, &Type))
|
|
{
|
|
if (Prefix == SCANF_PREFIX_LONG &&
|
|
(Type == SCANF_TYPE_STRING || Type == SCANF_TYPE_CHAR))
|
|
{
|
|
int len = 0;
|
|
WCHAR *charPtr = 0;
|
|
|
|
/* a single character */
|
|
if (Type == SCANF_TYPE_CHAR && Width == -1)
|
|
{
|
|
len = Width = 1;
|
|
}
|
|
|
|
/* calculate length of string to copy */
|
|
while (Buff[len] && !isspace(Buff[len]))
|
|
{
|
|
if (Width != -1 && len >= Width)
|
|
{
|
|
break;
|
|
}
|
|
++len;
|
|
}
|
|
|
|
if (Store)
|
|
{
|
|
int i;
|
|
charPtr = va_arg(ap, WCHAR *);
|
|
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
charPtr[i] = Buff[i];
|
|
}
|
|
if (Type == SCANF_TYPE_STRING)
|
|
{
|
|
/* end string */
|
|
charPtr[len] = 0;
|
|
}
|
|
++Length;
|
|
}
|
|
Buff += len;
|
|
}
|
|
/* this places the number of bytes stored into the next arg */
|
|
else if (Type == SCANF_TYPE_N)
|
|
{
|
|
if (Prefix == SCANF_PREFIX_SHORT)
|
|
{
|
|
*(va_arg(ap, short *)) = Buff - Buffer;
|
|
}
|
|
else
|
|
{
|
|
*(va_arg(ap, LPLONG)) = Buff - Buffer;
|
|
}
|
|
}
|
|
/* types that sscanf can handle */
|
|
else
|
|
{
|
|
int ret;
|
|
int n;
|
|
int size;
|
|
LPSTR newBuff = 0;
|
|
|
|
size = WideCharToMultiByte(CP_ACP, 0, Buff, -1, 0, 0, 0, 0);
|
|
if (!size)
|
|
{
|
|
ASSERT("WideCharToMultiByte failed. Error is %d\n",
|
|
GetLastError());
|
|
return -1;
|
|
}
|
|
newBuff = (LPSTR) malloc(size);
|
|
if (!newBuff)
|
|
{
|
|
ERROR("malloc failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return -1;
|
|
}
|
|
size = WideCharToMultiByte(CP_ACP, 0, Buff, size,
|
|
newBuff, size, 0, 0);
|
|
if (!size)
|
|
{
|
|
ASSERT("WideCharToMultiByte failed. Error is %d\n",
|
|
GetLastError());
|
|
free(newBuff);
|
|
return -1;
|
|
}
|
|
|
|
if (Store)
|
|
{
|
|
if (Type == SCANF_TYPE_BRACKETS)
|
|
{
|
|
WCHAR *strPtr;
|
|
int i;
|
|
|
|
/* add a '*' to %[] --> %*[] */
|
|
i = strlen(TempBuff) + 1;
|
|
while (i)
|
|
{
|
|
/* shift everything right one */
|
|
TempBuff[i] = TempBuff[i - 1];
|
|
--i;
|
|
}
|
|
TempBuff[0] = '%';
|
|
TempBuff[1] = '*';
|
|
|
|
/* %n doesn't count as a conversion. Since we're
|
|
suppressing conversion of the %[], sscanf will
|
|
always return 0, so we can't use the return value
|
|
to determine success. Set n to 0 before the call; if
|
|
it's still 0 afterwards, we know the call failed */
|
|
n = 0;
|
|
sscanf(newBuff, TempBuff, &n);
|
|
if(0 == n)
|
|
{
|
|
/* sscanf failed, nothing matched. set ret to 0,
|
|
so we know we have to break */
|
|
ret = 0;
|
|
}
|
|
else
|
|
{
|
|
strPtr = va_arg(ap, WCHAR *);
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
strPtr[i] = Buff[i];
|
|
}
|
|
strPtr[n] = 0; /* end string */
|
|
ret = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPVOID voidPtr;
|
|
voidPtr = va_arg(ap, LPVOID);
|
|
ret = sscanf(newBuff, TempBuff, voidPtr, &n);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = sscanf(newBuff, TempBuff, &n);
|
|
}
|
|
|
|
free(newBuff);
|
|
if (ret > 0)
|
|
{
|
|
Length += ret;
|
|
}
|
|
else
|
|
{
|
|
/* no match; break scan */
|
|
break;
|
|
}
|
|
Buff += n;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* grab, but not store */
|
|
if (*Fmt == *Buff && Type != SCANF_TYPE_SPACE)
|
|
{
|
|
++Fmt;
|
|
++Buff;
|
|
}
|
|
/* doesn't match, break scan */
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Length;
|
|
}
|
|
|
|
/*++
|
|
Function:
|
|
PAL_sscanf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_sscanf(
|
|
const char *buffer,
|
|
const char *format,
|
|
...)
|
|
{
|
|
int Length;
|
|
va_list ap;
|
|
|
|
ENTRY("PAL_sscanf (buffer=%p (%s), format=%p (%s))\n", buffer, buffer, format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_vsscanf(buffer, format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("PAL_sscanf returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
/*++
|
|
Function:
|
|
PAL_sprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_sprintf(
|
|
char *buffer,
|
|
const char *format,
|
|
...)
|
|
{
|
|
LONG Length;
|
|
va_list ap;
|
|
|
|
ENTRY("PAL_sprintf (buffer=%p, format=%p (%s))\n", buffer, format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_vsnprintf(buffer, 0x7fffffff, format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("PAL_sprintf returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
PAL_swprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_swprintf(
|
|
wchar_16 *buffer,
|
|
const wchar_16 *format,
|
|
...)
|
|
{
|
|
LONG Length;
|
|
va_list ap;
|
|
|
|
ENTRY("PAL_swprintf (buffer=%p, format=%p (%S))\n", buffer, format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_wvsnprintf(buffer, 0x7fffffff, format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("PAL_swprintf returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
/*++
|
|
Function:
|
|
PAL_swscanf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_swscanf(
|
|
const wchar_16 *buffer,
|
|
const wchar_16 *format,
|
|
...)
|
|
{
|
|
int Length;
|
|
va_list ap;
|
|
|
|
ENTRY("PAL_swscanf (buffer=%p (%S), format=%p (%S))\n", buffer, buffer, format, format);
|
|
|
|
va_start(ap, format);
|
|
Length = PAL_wvsscanf(buffer, format, ap);
|
|
va_end(ap);
|
|
|
|
LOGEXIT("PAL_swscanf returns int %d\n", Length);
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
PAL_vsprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_vsprintf(char *buffer,
|
|
const char *format,
|
|
va_list argptr)
|
|
{
|
|
LONG Length;
|
|
|
|
ENTRY("PAL_vsprintf (buffer=%p, format=%p (%s), argptr=%p)\n",
|
|
buffer, format, format, argptr);
|
|
|
|
Length = PAL_vsnprintf(buffer, 0x7fffffff, format, argptr);
|
|
|
|
LOGEXIT("PAL_vsprintf returns int %d\n", Length);
|
|
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
_vsnprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
_vsnprintf(char *buffer,
|
|
size_t count,
|
|
const char *format,
|
|
va_list argptr)
|
|
{
|
|
LONG Length;
|
|
|
|
ENTRY("_vsnprintf (buffer=%p, count=%d, format=%p (%s), argptr=%p)\n",
|
|
buffer, count, format, format, argptr);
|
|
|
|
Length = PAL_vsnprintf(buffer, count, format, argptr);
|
|
|
|
LOGEXIT("_vsnprintf returns int %d\n", Length);
|
|
|
|
return Length;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
Function:
|
|
PAL_vswprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
PAL_vswprintf(wchar_16 *buffer,
|
|
const wchar_16 *format,
|
|
va_list argptr)
|
|
{
|
|
LONG Length;
|
|
|
|
ENTRY("PAL_vswprintf (buffer=%p, format=%p (%S), argptr=%p)\n",
|
|
buffer, format, format, argptr);
|
|
|
|
Length = PAL_wvsnprintf(buffer, 0x7fffffff, format, argptr);
|
|
|
|
LOGEXIT("PAL_vswprintf returns int %d\n", Length);
|
|
|
|
return Length;
|
|
}
|
|
|
|
|
|
/*++
|
|
Function:
|
|
_vsnwprintf
|
|
|
|
See MSDN doc.
|
|
--*/
|
|
int
|
|
__cdecl
|
|
_vsnwprintf(wchar_16 *buffer,
|
|
size_t count,
|
|
const wchar_16 *format,
|
|
va_list argptr)
|
|
{
|
|
LONG Length;
|
|
|
|
ENTRY("_vsnwprintf (buffer=%p, count=%lu, format=%p (%S), argptr=%p)\n",
|
|
buffer, (unsigned long) count, format, format, argptr);
|
|
|
|
Length = PAL_wvsnprintf(buffer, count, format, argptr);
|
|
|
|
LOGEXIT("_vsnwprintf returns int %d\n", Length);
|
|
|
|
return Length;
|
|
}
|
|
|
|
|
|
|