941 lines
30 KiB
C++
941 lines
30 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Copyright (C) 1997, Microsoft Corporation.
|
||
|
//
|
||
|
// File: OutFmt.cxx
|
||
|
//
|
||
|
// Contents: COutputFormat
|
||
|
//
|
||
|
// History: 11-Jun-97 KyleP Moved from WQIter.cxx
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.cxx>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
static WCHAR * wcsDefaultBoolVectorPrefix = L" ";
|
||
|
static WCHAR * wcsDefaultBoolVectorSeparator = L" ";
|
||
|
static WCHAR * wcsDefaultBoolVectorSuffix = L" ";
|
||
|
static WCHAR * wcsDefaultCurrencyVectorPrefix = L" ";
|
||
|
static WCHAR * wcsDefaultCurrencyVectorSeparator = L" ";
|
||
|
static WCHAR * wcsDefaultCurrencyVectorSuffix = L" ";
|
||
|
static WCHAR * wcsDefaultDateVectorPrefix = L" ";
|
||
|
static WCHAR * wcsDefaultDateVectorSeparator = L" ";
|
||
|
static WCHAR * wcsDefaultDateVectorSuffix = L" ";
|
||
|
static WCHAR * wcsDefaultNumberVectorPrefix = L" ";
|
||
|
static WCHAR * wcsDefaultNumberVectorSeparator = L" ";
|
||
|
static WCHAR * wcsDefaultNumberVectorSuffix = L" ";
|
||
|
static WCHAR * wcsDefaultStringVectorPrefix = L" ";
|
||
|
static WCHAR * wcsDefaultStringVectorSeparator = L" ";
|
||
|
static WCHAR * wcsDefaultStringVectorSuffix = L" ";
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::COutputFormat - public
|
||
|
//
|
||
|
// Arguments: [webServer] - makes a copy of the web server to resolve CGI
|
||
|
// variables
|
||
|
//
|
||
|
// Synopsis: Constructor
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
// 96-Feb-26 DwightKr Added vector formatting
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
COutputFormat::COutputFormat( CWebServer & webServer )
|
||
|
: CWebServer( webServer ),
|
||
|
_wcsBoolVectorPrefix( wcsDefaultBoolVectorPrefix ),
|
||
|
_wcsBoolVectorSeparator( wcsDefaultBoolVectorSeparator ),
|
||
|
_wcsBoolVectorSuffix( wcsDefaultBoolVectorSuffix ),
|
||
|
_wcsCurrencyVectorPrefix( wcsDefaultCurrencyVectorPrefix ),
|
||
|
_wcsCurrencyVectorSeparator( wcsDefaultCurrencyVectorSeparator ),
|
||
|
_wcsCurrencyVectorSuffix( wcsDefaultCurrencyVectorSuffix ),
|
||
|
_wcsDateVectorPrefix( wcsDefaultDateVectorPrefix ),
|
||
|
_wcsDateVectorSeparator( wcsDefaultDateVectorSeparator ),
|
||
|
_wcsDateVectorSuffix( wcsDefaultDateVectorSuffix ),
|
||
|
_wcsNumberVectorPrefix( wcsDefaultNumberVectorPrefix ),
|
||
|
_wcsNumberVectorSeparator( wcsDefaultNumberVectorSeparator ),
|
||
|
_wcsNumberVectorSuffix( wcsDefaultNumberVectorSuffix ),
|
||
|
_wcsStringVectorPrefix( wcsDefaultStringVectorPrefix ),
|
||
|
_wcsStringVectorSeparator( wcsDefaultStringVectorSeparator ),
|
||
|
_wcsStringVectorSuffix( wcsDefaultStringVectorSuffix )
|
||
|
{
|
||
|
_numberFormat.lpDecimalSep = 0;
|
||
|
_numberFormat.lpThousandSep = 0;
|
||
|
|
||
|
_currencyFormat.lpDecimalSep = 0;
|
||
|
_currencyFormat.lpThousandSep = 0;
|
||
|
_currencyFormat.lpCurrencySymbol = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::GetIntegerFormat - private
|
||
|
//
|
||
|
// Synopsis: Formats a number and returns results in the string
|
||
|
// buffer supplied.
|
||
|
//
|
||
|
// Arguments: [wcsInput] - string to convert
|
||
|
// [wcsNumber] - output location for results
|
||
|
// [_cwcNumber] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
int COutputFormat::GetIntegerFormat( WCHAR * const wcsInput,
|
||
|
WCHAR * wcsNumber,
|
||
|
ULONG cwcNumber )
|
||
|
{
|
||
|
Win4Assert( 0 != _numberFormat.lpDecimalSep );
|
||
|
Win4Assert( 0 != _numberFormat.lpThousandSep );
|
||
|
Win4Assert( InvalidLCID != GetLCID() );
|
||
|
|
||
|
ULONG numDigits = _numberFormat.NumDigits;
|
||
|
_numberFormat.NumDigits = 0;
|
||
|
|
||
|
int cwcResult = ::GetNumberFormat( GetLCID(),
|
||
|
0,
|
||
|
wcsInput,
|
||
|
&_numberFormat,
|
||
|
wcsNumber,
|
||
|
cwcNumber );
|
||
|
|
||
|
_numberFormat.NumDigits = numDigits;
|
||
|
|
||
|
if ( 0 == cwcResult )
|
||
|
{
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
|
||
|
return cwcResult - 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::FormatNumber - public
|
||
|
//
|
||
|
// Synopsis: Formats a unsigned number and returns results in the string
|
||
|
// buffer supplied.
|
||
|
//
|
||
|
// Arguments: [ulNumber] - number to convert
|
||
|
// [wcsNumber] - output location for results
|
||
|
// [cwcNumber] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
int COutputFormat::FormatNumber( ULONG ulNumber,
|
||
|
WCHAR * wcsNumber,
|
||
|
ULONG cwcNumber )
|
||
|
{
|
||
|
WCHAR wcsBuffer[40];
|
||
|
IDQ_ultow( ulNumber, wcsBuffer );
|
||
|
|
||
|
return GetIntegerFormat( wcsBuffer, wcsNumber, cwcNumber );
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::FormatNumber
|
||
|
//
|
||
|
// Synopsis: Formats a signed number and returns results in the string
|
||
|
// buffer supplied.
|
||
|
//
|
||
|
// Arguments: [lNumber] - number to convert
|
||
|
// [wcsNumber] - output location for results
|
||
|
// [cwcNumber] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
int COutputFormat::FormatNumber( LONG lNumber,
|
||
|
WCHAR * wcsNumber,
|
||
|
ULONG cwcNumber )
|
||
|
{
|
||
|
WCHAR wcsBuffer[40];
|
||
|
IDQ_ltow( lNumber, wcsBuffer );
|
||
|
|
||
|
return GetIntegerFormat( wcsBuffer, wcsNumber, cwcNumber );
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::FormatNumber
|
||
|
//
|
||
|
// Synopsis: Formats a _int64 and returns results in the string
|
||
|
// buffer supplied.
|
||
|
//
|
||
|
// Arguments: [i64Number] - number to convert
|
||
|
// [wcsNumber] - output location for results
|
||
|
// [cwcNumber] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
int COutputFormat::FormatNumber( _int64 i64Number,
|
||
|
WCHAR * wcsNumber,
|
||
|
ULONG cwcNumber )
|
||
|
{
|
||
|
WCHAR wcsBuffer[40];
|
||
|
IDQ_lltow( i64Number, wcsBuffer );
|
||
|
|
||
|
return GetIntegerFormat( wcsBuffer, wcsNumber, cwcNumber );
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::FormatNumber
|
||
|
//
|
||
|
// Synopsis: Formats a unsigned _int64 and returns results in the string
|
||
|
// buffer supplied.
|
||
|
//
|
||
|
// Arguments: [ui64Number] - number to convert
|
||
|
// [wcsNumber] - output location for results
|
||
|
// [cwcNumber] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
int COutputFormat::FormatNumber( unsigned _int64 ui64Number,
|
||
|
WCHAR * wcsNumber,
|
||
|
ULONG cwcNumber )
|
||
|
{
|
||
|
WCHAR wcsBuffer[40];
|
||
|
IDQ_ulltow( ui64Number, wcsBuffer );
|
||
|
|
||
|
return GetIntegerFormat( wcsBuffer, wcsNumber, cwcNumber );
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: COutputFormat::FormatFloatRaw, public
|
||
|
//
|
||
|
// Synopsis: Formats a floating point number and returns results in the
|
||
|
// string buffer supplied.
|
||
|
//
|
||
|
// Arguments: [flt] - number to be formatted
|
||
|
// [cchPrec] - number of digits of precision to use
|
||
|
// [pwszNumber] - output location for results
|
||
|
// [cchNumber] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// Notes: GetNumberFormat isn't really very useful for numbers with
|
||
|
// very large or small magnitudes. It gives up when there are
|
||
|
// about 100 digits to the left of the decimal place.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
// 96-May-22 DwightKr Increased buffer size
|
||
|
// 97-Mar-12 AlanW Changed signature to better handle
|
||
|
// single-precision floating point
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int COutputFormat::FormatFloatRaw( double flt,
|
||
|
unsigned cchPrec,
|
||
|
WCHAR * pwszNumber,
|
||
|
ULONG cchNumber )
|
||
|
{
|
||
|
int iDec, fSign;
|
||
|
char * pszCvt = _ecvt( flt, cchPrec, &iDec, &fSign );
|
||
|
|
||
|
WCHAR *pwsz = pwszNumber;
|
||
|
|
||
|
if (fSign)
|
||
|
*pwsz++ = L'-';
|
||
|
|
||
|
if (iDec <= 0)
|
||
|
{
|
||
|
*pwsz++ = L'.';
|
||
|
while (iDec < 0)
|
||
|
{
|
||
|
*pwsz++ = L'0';
|
||
|
iDec++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (unsigned i=0; i< cchPrec; i++)
|
||
|
{
|
||
|
*pwsz++ = *pszCvt++;
|
||
|
|
||
|
if (iDec && --iDec == 0)
|
||
|
*pwsz++ = L'.';
|
||
|
}
|
||
|
|
||
|
while (iDec > 0)
|
||
|
{
|
||
|
*pwsz++ = L'0';
|
||
|
iDec--;
|
||
|
}
|
||
|
*pwsz = L'\0';
|
||
|
|
||
|
int cchResult = (int)(pwsz - pwszNumber);
|
||
|
Win4Assert ((unsigned)cchResult < cchNumber);
|
||
|
|
||
|
if ((unsigned)cchResult >= cchNumber)
|
||
|
{
|
||
|
ciGibDebugOut((DEB_WARN, "FormatFloatRaw - string buffer overflow!\n"));
|
||
|
cchResult = -1;
|
||
|
}
|
||
|
|
||
|
return cchResult;
|
||
|
} //FormatFloatRaw
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: COutputFormat::FormatFloat, public
|
||
|
//
|
||
|
// Synopsis: Formats a floating point number and returns results in the
|
||
|
// string buffer supplied.
|
||
|
//
|
||
|
// Arguments: [flt] - number to be formatted
|
||
|
// [cchPrec] - number of digits of precision to use
|
||
|
// [pwszNumber] - output location for results
|
||
|
// [cchNumber] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// Notes: GetNumberFormat isn't really very useful for numbers with
|
||
|
// very large or small magnitudes. It gives up when there are
|
||
|
// about 100 digits to the left of the decimal place.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
// 96-May-22 DwightKr Increased buffer size
|
||
|
// 97-Mar-12 AlanW Changed signature to better handle
|
||
|
// single-precision floating point
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int COutputFormat::FormatFloat( double flt,
|
||
|
unsigned cchPrec,
|
||
|
WCHAR * pwszNumber,
|
||
|
ULONG cchNumber )
|
||
|
{
|
||
|
Win4Assert( 0 != _numberFormat.lpDecimalSep );
|
||
|
Win4Assert( 0 != _numberFormat.lpThousandSep );
|
||
|
Win4Assert( InvalidLCID != GetLCID() );
|
||
|
|
||
|
WCHAR pwszInput[-DBL_MIN_10_EXP + DBL_DIG + 4];
|
||
|
WCHAR *pwsz = pwszInput;
|
||
|
|
||
|
int cch = FormatFloatRaw( flt,
|
||
|
cchPrec,
|
||
|
pwszInput,
|
||
|
sizeof pwszInput / sizeof pwszInput[0]);
|
||
|
|
||
|
Win4Assert( cch > 0 );
|
||
|
|
||
|
int cchResult = ::GetNumberFormat( GetLCID(),
|
||
|
0,
|
||
|
pwszInput,
|
||
|
&_numberFormat,
|
||
|
pwszNumber,
|
||
|
cchNumber );
|
||
|
|
||
|
if ( 0 == cchResult )
|
||
|
{
|
||
|
ciGibDebugOut(( DEB_WARN, "FormatFloat - GetNumberFormat failed, error = %d\n", GetLastError() ));
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
|
||
|
return cchResult - 1;
|
||
|
} //FormatFloat
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::FormatDate
|
||
|
//
|
||
|
// Synopsis: Formats a SYSTEMTIME and returns results in the string
|
||
|
// buffer supplied.
|
||
|
//
|
||
|
// Arguments: [sysTime] - date to convert
|
||
|
// [wcsDate] - output location for results
|
||
|
// [cwcDate] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int COutputFormat::FormatDate(
|
||
|
SYSTEMTIME & sysTime,
|
||
|
WCHAR * wcsDate,
|
||
|
ULONG cwcDate )
|
||
|
{
|
||
|
*wcsDate = 0;
|
||
|
Win4Assert( InvalidLCID != GetLCID() );
|
||
|
|
||
|
ULONG ulMethod = TheIDQRegParams.GetDateTimeFormatting();
|
||
|
|
||
|
// Fixed, non-localized formatting
|
||
|
|
||
|
if ( IS_DATETIME_FORMATTING_FAST_LCID == ulMethod )
|
||
|
{
|
||
|
if ( cwcDate < 10 )
|
||
|
return 0;
|
||
|
|
||
|
wsprintf( wcsDate, L"%4d/%02d/%02d",
|
||
|
(DWORD) sysTime.wYear,
|
||
|
(DWORD) sysTime.wMonth,
|
||
|
(DWORD) sysTime.wDay );
|
||
|
return 10;
|
||
|
}
|
||
|
|
||
|
// Format the date using the locale provided.
|
||
|
|
||
|
ULONG ulFlags = DATE_SHORTDATE;
|
||
|
|
||
|
if ( IS_DATETIME_FORMATTING_SYSTEM_LCID == ulMethod )
|
||
|
ulFlags |= LOCALE_NOUSEROVERRIDE;
|
||
|
|
||
|
ULONG cwcUsed = GetDateFormat( GetLCID(),
|
||
|
ulFlags,
|
||
|
&sysTime,
|
||
|
0,
|
||
|
wcsDate,
|
||
|
cwcDate );
|
||
|
|
||
|
if ( 0 != cwcUsed )
|
||
|
{
|
||
|
Win4Assert( 0 == wcsDate[cwcUsed - 1] );
|
||
|
|
||
|
// cwcUsed includes the null termination -- remove it.
|
||
|
|
||
|
return cwcUsed - 1;
|
||
|
}
|
||
|
|
||
|
#if DBG == 1
|
||
|
|
||
|
ULONG error = GetLastError();
|
||
|
|
||
|
ciGibDebugOut(( DEB_ERROR,
|
||
|
"GetDateFormat failed: 0x%x\n",
|
||
|
error ));
|
||
|
|
||
|
// ERROR_INVALID_PARAMETER indicates that the date is
|
||
|
// bogus -- perhaps because the file was deleted.
|
||
|
|
||
|
if ( ERROR_INVALID_PARAMETER != error )
|
||
|
Win4Assert( !"GetTimeFormat failed" );
|
||
|
|
||
|
#endif // DBG == 1
|
||
|
|
||
|
return 0;
|
||
|
} //FormatDate
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::FormatTime
|
||
|
//
|
||
|
// Synopsis: Formats a SYSTEMTIME and returns results in the string
|
||
|
// buffer supplied.
|
||
|
//
|
||
|
// Arguments: [sysTime] - date to convert
|
||
|
// [wcsTime] - output location for results
|
||
|
// [cwcTime] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int COutputFormat::FormatTime(
|
||
|
SYSTEMTIME & sysTime,
|
||
|
WCHAR * wcsTime,
|
||
|
ULONG cwcTime )
|
||
|
{
|
||
|
*wcsTime = 0;
|
||
|
Win4Assert( InvalidLCID != GetLCID() );
|
||
|
|
||
|
ULONG ulMethod = TheIDQRegParams.GetDateTimeFormatting();
|
||
|
|
||
|
// Fixed, non-localized formatting
|
||
|
|
||
|
if ( IS_DATETIME_FORMATTING_FAST_LCID == ulMethod )
|
||
|
{
|
||
|
if ( cwcTime < 8 )
|
||
|
return 0;
|
||
|
|
||
|
wsprintf( wcsTime, L"%2d:%02d:%02d",
|
||
|
(DWORD) sysTime.wHour,
|
||
|
(DWORD) sysTime.wMinute,
|
||
|
(DWORD) sysTime.wSecond );
|
||
|
return 8;
|
||
|
}
|
||
|
|
||
|
// Format the time using the locale provided.
|
||
|
|
||
|
ULONG ulFlags = ( IS_DATETIME_FORMATTING_USER_LCID == ulMethod ) ?
|
||
|
0 : LOCALE_NOUSEROVERRIDE;
|
||
|
|
||
|
ULONG cwcUsed = GetTimeFormat( GetLCID(),
|
||
|
ulFlags,
|
||
|
&sysTime,
|
||
|
0,
|
||
|
wcsTime,
|
||
|
cwcTime );
|
||
|
|
||
|
if ( 0 != cwcUsed )
|
||
|
{
|
||
|
Win4Assert( 0 == wcsTime[cwcUsed - 1] );
|
||
|
|
||
|
// cwcUsed includes the null termination -- remove it.
|
||
|
|
||
|
return cwcUsed - 1;
|
||
|
}
|
||
|
|
||
|
#if DBG == 1
|
||
|
|
||
|
ULONG error = GetLastError();
|
||
|
|
||
|
ciGibDebugOut(( DEB_ERROR,
|
||
|
"GetTimeFormat failed: 0x%x\n",
|
||
|
error ));
|
||
|
|
||
|
// ERROR_INVALID_PARAMETER indicates that the date is
|
||
|
// bogus -- perhaps because the file was deleted.
|
||
|
|
||
|
if ( ERROR_INVALID_PARAMETER != error )
|
||
|
Win4Assert( !"GetTimeFormat failed" );
|
||
|
|
||
|
#endif // DBG == 1
|
||
|
|
||
|
return 0;
|
||
|
} //FormatTime
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::FormatDateTime
|
||
|
//
|
||
|
// Synopsis: Formats a SYSTEMTIME and returns results in the string
|
||
|
// buffer supplied.
|
||
|
//
|
||
|
// Arguments: [sysTime] - date to convert
|
||
|
// [wcsDate] - output location for results
|
||
|
// [cwcDate] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int COutputFormat::FormatDateTime( SYSTEMTIME & SysTime,
|
||
|
WCHAR * wcsDate,
|
||
|
ULONG cwcDate )
|
||
|
{
|
||
|
//
|
||
|
// Convert UTC/GMT to local system time if set in the registry
|
||
|
//
|
||
|
|
||
|
if ( TheIDQRegParams.GetDateTimeLocal() )
|
||
|
{
|
||
|
FILETIME ft, ftLocal;
|
||
|
SystemTimeToFileTime( &SysTime, &ft );
|
||
|
FileTimeToLocalFileTime( &ft, &ftLocal );
|
||
|
FileTimeToSystemTime( &ftLocal, &SysTime );
|
||
|
}
|
||
|
|
||
|
int cwcDateBuffer = FormatDate( SysTime, wcsDate, cwcDate );
|
||
|
|
||
|
wcsDate[cwcDateBuffer] = L' ';
|
||
|
|
||
|
int cwcBuffer = max( 0, ( (int) (cwcDate - cwcDateBuffer ) ) - 2 );
|
||
|
|
||
|
int cwcTimeBuffer = FormatTime( SysTime,
|
||
|
wcsDate+cwcDateBuffer+1,
|
||
|
cwcBuffer );
|
||
|
|
||
|
return cwcTimeBuffer + cwcDateBuffer + 1;
|
||
|
} //FormatDateTime
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::FormatCurrency
|
||
|
//
|
||
|
// Synopsis: Formats a CY and returns results in the string
|
||
|
// buffer supplied.
|
||
|
//
|
||
|
// Arguments: [cyValue] - number to convert
|
||
|
// [wcsCurrency] - output location for results
|
||
|
// [cwcCurrency] - length of output buffer in WCHARs
|
||
|
//
|
||
|
// Returns: The number of characters in the final string, less the NULL
|
||
|
// terminator.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
int COutputFormat::FormatCurrency( CY cyValue,
|
||
|
WCHAR * wcsCurrency,
|
||
|
ULONG cwcCurrency )
|
||
|
{
|
||
|
Win4Assert( 0 != _numberFormat.lpDecimalSep );
|
||
|
Win4Assert( 0 != _numberFormat.lpThousandSep );
|
||
|
Win4Assert( 0 != _currencyFormat.lpDecimalSep );
|
||
|
Win4Assert( 0 != _currencyFormat.lpThousandSep );
|
||
|
Win4Assert( InvalidLCID != GetLCID() );
|
||
|
|
||
|
WCHAR wcsBuffer[320];
|
||
|
double dblValue;
|
||
|
VarR8FromCy( cyValue, &dblValue );
|
||
|
|
||
|
swprintf( wcsBuffer, L"%lf", dblValue );
|
||
|
|
||
|
int cwcResult = ::GetCurrencyFormat( GetLCID(),
|
||
|
0,
|
||
|
wcsBuffer,
|
||
|
&_currencyFormat,
|
||
|
wcsCurrency,
|
||
|
cwcCurrency );
|
||
|
if ( 0 == cwcResult )
|
||
|
{
|
||
|
THROW( CException() );
|
||
|
}
|
||
|
|
||
|
return cwcResult - 1;
|
||
|
} //FormatCurrency
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::LoadNumberFormatInfo - public
|
||
|
//
|
||
|
// Synopsis: Fills the numberFormat stucture with formatting information
|
||
|
// used to subsequently format numbers.
|
||
|
//
|
||
|
// History: 97-Jun-24 t-elainc Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void COutputFormat::LoadNumberFormatInfo( LCID lcid )
|
||
|
{
|
||
|
LoadNumberFormatInfo(lcid, LocaleToCodepage(lcid) );
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ConvertGroupingStringToInt
|
||
|
//
|
||
|
// Synopsis: Converts a grouping string from the registry to an integer,
|
||
|
// as required by the Win32 number formatting API
|
||
|
//
|
||
|
// History: 5-Feb-99 dlee Stole from the Win32 implementation
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
int ConvertGroupingStringToInt( WCHAR const * pwcGrouping )
|
||
|
{
|
||
|
XGrowable<WCHAR> xDest( 1 + wcslen( pwcGrouping ) );
|
||
|
WCHAR * pDest = xDest.Get();
|
||
|
|
||
|
//
|
||
|
// Filter out all non-numeric values and all zero values.
|
||
|
// Store the result in the destination buffer.
|
||
|
//
|
||
|
|
||
|
WCHAR const * pSrc = pwcGrouping;
|
||
|
|
||
|
while (0 != *pSrc)
|
||
|
{
|
||
|
if ( ( *pSrc < L'1' ) || ( *pSrc > L'9' ) )
|
||
|
{
|
||
|
pSrc++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pSrc != pDest)
|
||
|
*pDest = *pSrc;
|
||
|
|
||
|
pSrc++;
|
||
|
pDest++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure there is something in the destination buffer.
|
||
|
// Also, see if we need to add a zero in the case of 3;2 becomes 320.
|
||
|
//
|
||
|
|
||
|
if ( ( pDest == xDest.Get() ) || ( *(pSrc - 1) != L'0' ) )
|
||
|
{
|
||
|
*pDest = L'0';
|
||
|
pDest++;
|
||
|
}
|
||
|
|
||
|
// Null terminate the buffer.
|
||
|
|
||
|
*pDest = 0;
|
||
|
|
||
|
// Convert the string to an integer.
|
||
|
|
||
|
return _wtoi( xDest.Get() );
|
||
|
} //ConvertGroupingStringToInt
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: COutputFormat::LoadNumberFormatInfo - public
|
||
|
//
|
||
|
// Synopsis: Fills the numberFormat stucture with formatting information
|
||
|
// used to subsequently format numbers.
|
||
|
//
|
||
|
// History: 96-Jan-18 DwightKr Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void COutputFormat::LoadNumberFormatInfo( LCID lcid , ULONG codepage)
|
||
|
{
|
||
|
Win4Assert( InvalidLCID != lcid );
|
||
|
|
||
|
//
|
||
|
// If we're already loaded, then don't do it again.
|
||
|
//
|
||
|
|
||
|
if ( lcid == GetLCID() && 0 != _numberFormat.lpDecimalSep )
|
||
|
return;
|
||
|
|
||
|
delete _numberFormat.lpDecimalSep;
|
||
|
delete _numberFormat.lpThousandSep;
|
||
|
delete _currencyFormat.lpDecimalSep;
|
||
|
delete _currencyFormat.lpThousandSep;
|
||
|
|
||
|
_numberFormat.lpDecimalSep = 0;
|
||
|
_numberFormat.lpThousandSep = 0;
|
||
|
_currencyFormat.lpDecimalSep = 0;
|
||
|
_currencyFormat.lpThousandSep = 0;
|
||
|
|
||
|
Win4Assert( 0 == _numberFormat.lpDecimalSep );
|
||
|
Win4Assert( 0 == _numberFormat.lpThousandSep );
|
||
|
Win4Assert( 0 == _currencyFormat.lpDecimalSep );
|
||
|
Win4Assert( 0 == _currencyFormat.lpThousandSep );
|
||
|
|
||
|
SetLCID( lcid, 0, 0 );
|
||
|
|
||
|
TheFormattingCache.GetFormattingInfo( lcid,
|
||
|
_numberFormat,
|
||
|
_currencyFormat );
|
||
|
|
||
|
SetCodePage( codepage );
|
||
|
|
||
|
ciGibDebugOut(( DEB_ITRACE, "Using a codePage of 0x%x for locale 0x%x\n",
|
||
|
CodePage(),
|
||
|
GetLCID() ));
|
||
|
} //LoadNumberFormatInfo
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CFormatItem::CFormatItem, public
|
||
|
//
|
||
|
// Synopsis: Constructs formatting info.
|
||
|
//
|
||
|
// Arguments: [lcid] -- The locale to use.
|
||
|
//
|
||
|
// History: 99-Feb-10 dlee Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CFormatItem::CFormatItem( LCID lcid ) : _lcid( lcid )
|
||
|
{
|
||
|
WCHAR wcsBuffer[256];
|
||
|
|
||
|
RtlZeroMemory( &_numberFormat, sizeof _numberFormat );
|
||
|
RtlZeroMemory( &_currencyFormat, sizeof _currencyFormat );
|
||
|
|
||
|
// Get the number of decimal digits.
|
||
|
GetLocaleInfo(lcid, LOCALE_IDIGITS, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
_numberFormat.NumDigits = _wtoi(wcsBuffer);
|
||
|
|
||
|
// Get the leading zero in decimal fields option.
|
||
|
GetLocaleInfo(lcid, LOCALE_ILZERO, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
_numberFormat.LeadingZero = _wtoi(wcsBuffer);
|
||
|
|
||
|
// Get the negative ordering.
|
||
|
GetLocaleInfo(lcid, LOCALE_INEGNUMBER, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
_numberFormat.NegativeOrder = _wtoi(wcsBuffer);
|
||
|
|
||
|
// Get the grouping left of the decimal.
|
||
|
GetLocaleInfo(lcid, LOCALE_SGROUPING, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
_numberFormat.Grouping = ConvertGroupingStringToInt( wcsBuffer );
|
||
|
ciGibDebugOut(( DEB_ITRACE, "grouping '%ws' -> %d\n",
|
||
|
wcsBuffer, _numberFormat.Grouping ));
|
||
|
|
||
|
// Get the decimal separator.
|
||
|
GetLocaleInfo(lcid, LOCALE_SDECIMAL, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
XPtrST<WCHAR> xNumDecimalSep( CopyString( wcsBuffer ) );
|
||
|
_numberFormat.lpDecimalSep = xNumDecimalSep.GetPointer();
|
||
|
|
||
|
// Get the thousand separator.
|
||
|
GetLocaleInfo(lcid, LOCALE_STHOUSAND, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
XPtrST<WCHAR> xNumThousandSep( CopyString( wcsBuffer ) );
|
||
|
_numberFormat.lpThousandSep = xNumThousandSep.GetPointer();
|
||
|
|
||
|
// Get the number of currency digits.
|
||
|
GetLocaleInfo(lcid, LOCALE_ICURRDIGITS, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
_currencyFormat.NumDigits = _wtoi(wcsBuffer);
|
||
|
|
||
|
GetLocaleInfo(lcid, LOCALE_ILZERO, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
// Get the leading zero in currency fields option.
|
||
|
_currencyFormat.LeadingZero = _wtoi(wcsBuffer);
|
||
|
|
||
|
// Get the currency grouping left of the decimal.
|
||
|
GetLocaleInfo(lcid, LOCALE_SMONGROUPING, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
_currencyFormat.Grouping = _wtoi(wcsBuffer);
|
||
|
|
||
|
// Get the currency decimal separator.
|
||
|
GetLocaleInfo(lcid, LOCALE_SMONDECIMALSEP, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
XPtrST<WCHAR> xCurDecimalSep( CopyString( wcsBuffer ) );
|
||
|
_currencyFormat.lpDecimalSep = xCurDecimalSep.GetPointer();
|
||
|
|
||
|
// Get the currency thousand separator.
|
||
|
GetLocaleInfo(lcid, LOCALE_SMONTHOUSANDSEP, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
XPtrST<WCHAR> xCurThousandSep( CopyString( wcsBuffer ) );
|
||
|
_currencyFormat.lpThousandSep = xCurThousandSep.GetPointer();
|
||
|
|
||
|
// Get the negative ordering.
|
||
|
GetLocaleInfo(lcid, LOCALE_INEGCURR, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
_currencyFormat.NegativeOrder = _wtoi(wcsBuffer);
|
||
|
|
||
|
// Get the positive ordering.
|
||
|
GetLocaleInfo(lcid, LOCALE_ICURRENCY, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
|
||
|
_currencyFormat.PositiveOrder = _wtoi(wcsBuffer);
|
||
|
|
||
|
_currencyFormat.lpCurrencySymbol = L"";
|
||
|
|
||
|
xNumDecimalSep.Acquire();
|
||
|
xNumThousandSep.Acquire();
|
||
|
xCurDecimalSep.Acquire();
|
||
|
xCurThousandSep.Acquire();
|
||
|
} //CFormatItem
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CFormatItem::~CFormatItem, public
|
||
|
//
|
||
|
// Synopsis: Frees formatting info.
|
||
|
//
|
||
|
// History: 99-Feb-10 dlee Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CFormatItem::~CFormatItem()
|
||
|
{
|
||
|
delete _numberFormat.lpDecimalSep;
|
||
|
delete _numberFormat.lpThousandSep;
|
||
|
delete _currencyFormat.lpDecimalSep;
|
||
|
delete _currencyFormat.lpThousandSep;
|
||
|
} //~CFormatItem
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CFormatItem::Copy, public
|
||
|
//
|
||
|
// Synopsis: Copies formatting info into the arguments
|
||
|
//
|
||
|
// Arguments: [numberFormat] -- Where the number format is copied to
|
||
|
// [currencyFormat] -- Where the currency format is copied to
|
||
|
//
|
||
|
// History: 99-Feb-10 dlee Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CFormatItem::Copy(
|
||
|
NUMBERFMT & numberFormat,
|
||
|
CURRENCYFMT & currencyFormat ) const
|
||
|
{
|
||
|
XPtrST<WCHAR> xNumDecimalSep( CopyString( _numberFormat.lpDecimalSep ) );
|
||
|
XPtrST<WCHAR> xNumThousandSep( CopyString( _numberFormat.lpThousandSep ) );
|
||
|
XPtrST<WCHAR> xCurDecimalSep( CopyString( _currencyFormat.lpDecimalSep ) );
|
||
|
XPtrST<WCHAR> xCurThousandSep( CopyString( _currencyFormat.lpDecimalSep ) );
|
||
|
|
||
|
RtlCopyMemory( &numberFormat, &_numberFormat, sizeof NUMBERFMT );
|
||
|
RtlCopyMemory( ¤cyFormat, &_currencyFormat, sizeof CURRENCYFMT );
|
||
|
|
||
|
numberFormat.lpDecimalSep = xNumDecimalSep.Acquire();
|
||
|
numberFormat.lpThousandSep = xNumThousandSep.Acquire();
|
||
|
currencyFormat.lpDecimalSep = xCurDecimalSep.Acquire();
|
||
|
currencyFormat.lpThousandSep = xCurThousandSep.Acquire();
|
||
|
} //Copy
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CFormattingCache::GetFormattingInfo, public
|
||
|
//
|
||
|
// Synopsis: Copies formatting info for lcid into the arguments
|
||
|
//
|
||
|
// Arguments: [lcid] -- Locale of info to lookup
|
||
|
// [numberFormat] -- Where the number format is copied to
|
||
|
// [currencyFormat] -- Where the currency format is copied to
|
||
|
//
|
||
|
// History: 99-Feb-10 dlee Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CFormattingCache::GetFormattingInfo(
|
||
|
LCID lcid,
|
||
|
NUMBERFMT & numberFormat,
|
||
|
CURRENCYFMT & currencyFormat )
|
||
|
{
|
||
|
CLock lock( _mutex );
|
||
|
|
||
|
for ( unsigned i = 0; i < _aItems.Count(); i++ )
|
||
|
{
|
||
|
if ( _aItems[i]->GetLCID() == lcid )
|
||
|
{
|
||
|
_aItems[i]->Copy( numberFormat, currencyFormat );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
XPtr<CFormatItem> xItem( new CFormatItem( lcid ) );
|
||
|
xItem->Copy( numberFormat, currencyFormat );
|
||
|
_aItems.Add( xItem.GetPointer(), _aItems.Count() );
|
||
|
xItem.Acquire();
|
||
|
} //GetFormattingInfo
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CFormattingCache::Purge, public
|
||
|
//
|
||
|
// Synopsis: Purges the cache of all entries
|
||
|
//
|
||
|
// History: 99-Feb-10 dlee Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CFormattingCache::Purge()
|
||
|
{
|
||
|
CLock lock( _mutex );
|
||
|
|
||
|
_aItems.Clear();
|
||
|
} //Purge
|
||
|
|