|
|
/*++
Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
Module Name:
number.c
Abstract:
This file contains functions that form properly formatted number and currency strings for a given locale.
APIs found in this file: GetNumberFormatW GetCurrencyFormatW
Revision History:
07-28-93 JulieB Created.
--*/
//
// Include Files.
//
#include "nls.h"
#include "nlssafe.h"
//
// Constant Declarations.
//
#define MAX_NUMBER_BUFFER 256 // size of static buffer
#define MAX_GROUPS 5 // max number of groupings
#define MAX_GROUPING_NUMBER 9999 // max value for groupings
//
// Account for:
// - number of fractional digits
// - decimal seperator
// - negative sign
// - zero terminator
//
#define MAX_NON_INTEGER_PART ( MAX_VALUE_IDIGITS + \
MAX_SDECIMAL + \ MAX_SNEGSIGN + \ 1 ) //
// Account for:
// - negative sign
// - blank spaces
// - one extra number from rounding
// - one extra grouping separator from rounding
//
#define MAX_NUMBER_EXTRAS ( MAX_SNEGSIGN + \
MAX_BLANKS + \ 1 + \ MAX_STHOUSAND ) //
// Account for:
// - negative sign
// - currency sign
// - blank spaces
// - one extra number from rounding
// - one extra grouping separator from rounding
//
#define MAX_CURRENCY_EXTRAS ( MAX_SNEGSIGN + \
MAX_SCURRENCY + \ MAX_BLANKS + \ 1 + \ MAX_SMONTHOUSEP )
//
// Forward Declarations.
//
BOOL IsValidNumberFormat( CONST NUMBERFMTW *pFormat);
BOOL IsValidCurrencyFormat( CONST CURRENCYFMTW *pFormat);
UINT GetRegIntValue( LCID Locale, LCTYPE LCType, BOOL NoUserOverride, SIZE_T CacheOffset, LPWSTR pRegVal, LPWSTR pDefault, int DefaultVal, int UpperBound);
int ConvertGroupingStringToInt( LPWSTR pGroupingSrc, LPWSTR pGroupingDest);
UINT GetGroupingValue( LCID Locale, LCTYPE LCType, BOOL NoUserOverride, SIZE_T CacheOffset, LPWSTR pRegVal, LPWSTR pDefault, int DefaultVal);
int GetNumberString( PLOC_HASH pHashN, LPWSTR pValue, LPNUMBERFMTW pFormat, LPWSTR *ppBuf, int BufSize, BOOL *pfZeroValue, int *pNeededSizeToAllocate, BOOL fSetError);
int ParseNumber( PLOC_HASH pHashN, BOOL NoUserOverride, LPWSTR pValue, LPNUMBERFMTW pFormat, LPWSTR *ppBuf, int BufSize, int *pNeededSizeToAllocate, BOOL fSetError);
int ParseCurrency( PLOC_HASH pHashN, BOOL NoUserOverride, LPWSTR pValue, LPCURRENCYFMTW pFormat, LPWSTR *ppBuf, int BufSize, int *pNeededSizeToAllocate, BOOL fSetError);
//-------------------------------------------------------------------------//
// INTERNAL MACROS //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// NLS_COPY_UNICODE_STR
//
// Copies a zero terminated Unicode string from pSrc to the pDest buffer.
// The pDest pointer is advanced to the end of the string.
//
// DEFINED AS A MACRO.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define NLS_COPY_UNICODE_STR( pDest, \
pSrc ) \ { \ LPWSTR pTmp; /* temp pointer to source */ \ \ \ pTmp = pSrc; \ while (*pTmp) \ { \ *pDest = *pTmp; \ pDest++; \ pTmp++; \ } \ }
////////////////////////////////////////////////////////////////////////////
//
// NLS_COPY_UNICODE_STR_NOADV
//
// Copies a zero terminated Unicode string from pSrc to the pDest buffer.
// The pDest pointer is NOT advanced to the end of the string.
//
// DEFINED AS A MACRO.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define NLS_COPY_UNICODE_STR_TMP( pDest, \
pSrc ) \ { \ LPWSTR pSrcT; /* temp pointer to source */ \ LPWSTR pDestT; /* temp pointer to destination */ \ \ \ pSrcT = pSrc; \ pDestT = pDest; \ while (*pSrcT) \ { \ *pDestT = *pSrcT; \ pDestT++; \ pSrcT++; \ } \ }
////////////////////////////////////////////////////////////////////////////
//
// NLS_ROUND_IT
//
// Rounds the floating point number given as a string.
//
// NOTE: This function will reset the pBegin pointer if an
// extra character is added to the string.
//
// DEFINED AS A MACRO.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define NLS_ROUND_IT( pBegin, \
pEnd, \ IntPartGroup, \ pSep ) \ { \ LPWSTR pRound = pEnd; /* ptr to position in string */ \ LPWSTR pEndSep; /* ptr to end of group separator */ \ \ \ /* \
* Round the digits in the string one by one, going backwards in \ * the string. Stop when either a value other than 9 is found, \ * or the beginning of the string is reached. \ */ \ while (pRound >= pBegin) \ { \ if ((*pRound < NLS_CHAR_ZERO) || (*pRound > NLS_CHAR_NINE)) \ { \ pRound--; \ } \ else if (*pRound == NLS_CHAR_NINE) \ { \ *pRound = NLS_CHAR_ZERO; \ pRound--; \ } \ else \ { \ (*pRound)++; \ break; \ } \ } \ \ /* \
* Make sure we don't have a number like 9.999, where we would need \ * to add an extra character to the string and make it 10.00. \ */ \ if (pRound < pBegin) \ { \ /* \
* All values to the right of the decimal are zero. All values \ * to the left of the decimal are either zero or the grouping \ * separator. \ */ \ if ((IntPartGroup) == 0) \ { \ /* \
* Adding another integer means we need to add another \ * grouping separator. \ */ \ pEndSep = pSep + NlsStrLenW(pSep) - 1; \ while (pEndSep >= pSep) \ { \ (pBegin)--; \ *(pBegin) = *pEndSep; \ pEndSep--; \ } \ } \ \ /* \
* Store a 1 at the beginning of the string and reset the \ * pointer to the beginning of the string. \ */ \ (pBegin)--; \ *(pBegin) = NLS_CHAR_ONE; \ } \ }
//-------------------------------------------------------------------------//
// API ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// GetNumberFormatW
//
// Returns a properly formatted number string for the given locale.
// This call also indicates how much memory is necessary to contain
// the desired information.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int WINAPI GetNumberFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST NUMBERFMTW *lpFormat, LPWSTR lpNumberStr, int cchNumber)
{ PLOC_HASH pHashN; // ptr to LOC hash node
int Length = 0; // number of characters written
LPNUMBERFMTW pFormat; // ptr to number format struct
NUMBERFMTW NumFmt; // number format
WCHAR pString[MAX_NUMBER_BUFFER]; // ptr to temporary buffer
LPWSTR pFinal; // ptr to the final string
BOOL NoUserOverride; // if no user override flag set
WCHAR pDecimal[MAX_REG_VAL_SIZE]; // temp buffer for decimal sep
WCHAR pThousand[MAX_REG_VAL_SIZE]; // temp buffer for thousand sep
int NeededSizeToAllocate = 0; // size of buffer needed
WCHAR *pTemp = NULL; // allocated temp storage buffer
//
// Initialize UserOverride.
//
NoUserOverride = dwFlags & LOCALE_NOUSEROVERRIDE;
//
// Invalid Parameter Check:
// - validate LCID
// - count is negative
// - NULL src string
// - NULL data pointer AND count is not zero
// - ptrs to string buffers same
//
VALIDATE_LOCALE(Locale, pHashN, FALSE); if ( (pHashN == NULL) || (cchNumber < 0) || (lpValue == NULL) || ((lpNumberStr == NULL) && (cchNumber != 0)) || (lpValue == lpNumberStr) ) { SetLastError(ERROR_INVALID_PARAMETER); return (0); }
//
// Invalid Flags Check:
// - flags other than valid ones
// - lpFormat not NULL AND NoUserOverride flag is set
//
if ( (dwFlags & GNF_INVALID_FLAG) || ((lpFormat != NULL) && (NoUserOverride)) ) { SetLastError(ERROR_INVALID_FLAGS); return (0); }
//
// Set pFormat to point at the proper format structure.
//
if (lpFormat != NULL) { //
// Use the format structure given by the caller.
//
pFormat = (LPNUMBERFMTW)lpFormat;
if (!IsValidNumberFormat(pFormat)) { SetLastError(ERROR_INVALID_PARAMETER); return (0); } } else { //
// Use the format structure defined here.
//
pFormat = &NumFmt;
//
// Get the number of decimal digits.
//
pFormat->NumDigits = GetRegIntValue( Locale, LOCALE_IDIGITS, NoUserOverride, FIELD_OFFSET(NLS_USER_INFO, iDigits), NLS_VALUE_IDIGITS, pHashN->pLocaleFixed->szIDigits, 2, MAX_VALUE_IDIGITS );
//
// Get the leading zero in decimal fields option.
//
pFormat->LeadingZero = GetRegIntValue( Locale, LOCALE_ILZERO, NoUserOverride, FIELD_OFFSET(NLS_USER_INFO, iLZero), NLS_VALUE_ILZERO, pHashN->pLocaleFixed->szILZero, 1, MAX_VALUE_ILZERO );
//
// Get the negative ordering.
//
pFormat->NegativeOrder = GetRegIntValue( Locale, LOCALE_INEGNUMBER, NoUserOverride, FIELD_OFFSET(NLS_USER_INFO, iNegNumber), NLS_VALUE_INEGNUMBER, pHashN->pLocaleFixed->szINegNumber, 1, MAX_VALUE_INEGNUMBER );
//
// Get the grouping left of the decimal.
//
pFormat->Grouping = GetGroupingValue( Locale, LOCALE_SGROUPING, NoUserOverride, FIELD_OFFSET(NLS_USER_INFO, sGrouping), NLS_VALUE_SGROUPING, (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SGrouping, 3 );
//
// Get the decimal separator.
//
// NOTE: This must follow the above calls because
// pDecSep is used as a temporary buffer above.
//
if ( (!NoUserOverride) && GetUserInfo( Locale, LOCALE_SDECIMAL, FIELD_OFFSET(NLS_USER_INFO, sDecimal), NLS_VALUE_SDECIMAL, pDecimal, ARRAYSIZE(pDecimal), TRUE ) && IsValidSeparatorString( pDecimal, MAX_SDECIMAL, FALSE ) ) { pFormat->lpDecimalSep = pDecimal; } else { pFormat->lpDecimalSep = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SDecimal; }
//
// Get the thousand separator.
// This string may be a null string.
//
if ( (!NoUserOverride) && GetUserInfo( Locale, LOCALE_STHOUSAND, FIELD_OFFSET(NLS_USER_INFO, sThousand), NLS_VALUE_STHOUSAND, pThousand, ARRAYSIZE(pThousand), FALSE ) && IsValidSeparatorString( pThousand, MAX_STHOUSAND, FALSE ) ) { pFormat->lpThousandSep = pThousand; } else { pFormat->lpThousandSep = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SThousand; } }
//
// Parse the number format string.
//
pFinal = pString; Length = ParseNumber( pHashN, NoUserOverride, (LPWSTR)lpValue, pFormat, &pFinal, MAX_NUMBER_BUFFER, &NeededSizeToAllocate, FALSE );
//
// If the failure is due to a stack variable size limitation, then
// try to satisfy the request from the local process heap.
//
if ((Length == 0) && (NeededSizeToAllocate > 0)) { pTemp = RtlAllocateHeap( RtlProcessHeap(), 0, NeededSizeToAllocate * sizeof(TCHAR) ); if (pTemp) { pFinal = pTemp; Length = ParseNumber( pHashN, NoUserOverride, (LPWSTR)lpValue, pFormat, &pFinal, NeededSizeToAllocate, &NeededSizeToAllocate, TRUE ); } }
//
// Check cchNumber for size of given buffer.
//
if ((cchNumber == 0) || (Length == 0)) { //
// If cchNumber is 0, then we can't use lpNumberStr. In this
// case, we simply want to return the length (in characters) of
// the string to be copied.
//
Length = Length; } else if (cchNumber < Length) { //
// The buffer is too small for the string, so return an error
// and zero bytes written.
//
SetLastError(ERROR_INSUFFICIENT_BUFFER); Length = 0; } else { //
// Copy the number string to lpNumberStr and null terminate it.
// Return the number of characters copied.
//
if(FAILED(StringCchCopyW(lpNumberStr, cchNumber, pFinal))) { //
// Failure should in theory be impossible, but if we ignore the
// return value, PREfast will complain.
//
SetLastError(ERROR_OUTOFMEMORY); Length = 0; } }
//
// Free any dynamically allocated memory.
//
if (pTemp != NULL) { RtlFreeHeap(RtlProcessHeap(), 0, pTemp); }
//
// Return the number of characters copied.
//
return (Length); }
////////////////////////////////////////////////////////////////////////////
//
// GetCurrencyFormatW
//
// Returns a properly formatted currency string for the given locale.
// This call also indicates how much memory is necessary to contain
// the desired information.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int WINAPI GetCurrencyFormatW( LCID Locale, DWORD dwFlags, LPCWSTR lpValue, CONST CURRENCYFMTW *lpFormat, LPWSTR lpCurrencyStr, int cchCurrency)
{ PLOC_HASH pHashN; // ptr to LOC hash node
int Length = 0; // number of characters written
LPCURRENCYFMTW pFormat; // ptr to currency format struct
CURRENCYFMTW CurrFmt; // currency format
WCHAR pString[MAX_NUMBER_BUFFER]; // ptr to temporary buffer
LPWSTR pFinal; // ptr to the final string
BOOL NoUserOverride; // if no user override flag set
WCHAR pDecimal[MAX_REG_VAL_SIZE]; // temp buffer for decimal sep
WCHAR pThousand[MAX_REG_VAL_SIZE]; // temp buffer for thousand sep
WCHAR pCurrency[MAX_REG_VAL_SIZE]; // temp buffer for currency symbol
int NeededSizeToAllocate = 0; // size of buffer needed
WCHAR *pTemp = NULL; // allocated temp storage buffer
//
// Initialize UserOverride.
//
NoUserOverride = dwFlags & LOCALE_NOUSEROVERRIDE;
//
// Invalid Parameter Check:
// - validate LCID
// - count is negative
// - NULL src string
// - NULL data pointer AND count is not zero
// - ptrs to string buffers same
//
VALIDATE_LOCALE(Locale, pHashN, FALSE); if ( (pHashN == NULL) || (cchCurrency < 0) || (lpValue == NULL) || ((lpCurrencyStr == NULL) && (cchCurrency != 0)) || (lpValue == lpCurrencyStr) ) { SetLastError(ERROR_INVALID_PARAMETER); return (0); }
//
// Invalid Flags Check:
// - flags other than valid ones
// - lpFormat not NULL AND NoUserOverride flag is set
//
if ( (dwFlags & GCF_INVALID_FLAG) || ((lpFormat != NULL) && (NoUserOverride)) ) { SetLastError(ERROR_INVALID_FLAGS); return (0); }
//
// Set pFormat to point at the proper format structure.
//
if (lpFormat != NULL) { //
// Use the format structure given by the caller.
//
pFormat = (LPCURRENCYFMTW)lpFormat;
if (!IsValidCurrencyFormat(pFormat)) { SetLastError(ERROR_INVALID_PARAMETER); return (0); } } else { //
// Use the format structure defined here.
//
pFormat = &CurrFmt;
//
// Get the number of decimal digits.
//
pFormat->NumDigits = GetRegIntValue( Locale, LOCALE_ICURRDIGITS, NoUserOverride, FIELD_OFFSET(NLS_USER_INFO, iCurrDigits), NLS_VALUE_ICURRDIGITS, pHashN->pLocaleFixed->szICurrDigits, 2, MAX_VALUE_ICURRDIGITS );
//
// Get the leading zero in decimal fields option.
//
pFormat->LeadingZero = GetRegIntValue( Locale, LOCALE_ILZERO, NoUserOverride, FIELD_OFFSET(NLS_USER_INFO, iLZero), NLS_VALUE_ILZERO, pHashN->pLocaleFixed->szILZero, 1, MAX_VALUE_ILZERO );
//
// Get the positive ordering.
//
pFormat->PositiveOrder = GetRegIntValue( Locale, LOCALE_ICURRENCY, NoUserOverride, FIELD_OFFSET(NLS_USER_INFO, iCurrency), NLS_VALUE_ICURRENCY, pHashN->pLocaleFixed->szICurrency, 0, MAX_VALUE_ICURRENCY );
//
// Get the negative ordering.
//
pFormat->NegativeOrder = GetRegIntValue( Locale, LOCALE_INEGCURR, NoUserOverride, FIELD_OFFSET(NLS_USER_INFO, iNegCurr), NLS_VALUE_INEGCURR, pHashN->pLocaleFixed->szINegCurr, 1, MAX_VALUE_INEGCURR );
//
// Get the grouping left of the decimal.
//
pFormat->Grouping = GetGroupingValue( Locale, LOCALE_SMONGROUPING, NoUserOverride, FIELD_OFFSET(NLS_USER_INFO, sMonGrouping), NLS_VALUE_SMONGROUPING, (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SMonGrouping, 3 );
//
// Get the decimal separator.
//
// NOTE: This must follow the above calls because
// pDecSep is used as a temporary buffer.
//
if ( (!NoUserOverride) && GetUserInfo( Locale, LOCALE_SMONDECIMALSEP, FIELD_OFFSET(NLS_USER_INFO, sMonDecSep), NLS_VALUE_SMONDECIMALSEP, pDecimal, ARRAYSIZE(pDecimal), TRUE ) && IsValidSeparatorString( pDecimal, MAX_SDECIMAL, FALSE ) ) { pFormat->lpDecimalSep = pDecimal; } else { pFormat->lpDecimalSep = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SMonDecSep; }
//
// Get the thousand separator.
// This string may be a null string.
//
if ( (!NoUserOverride) && GetUserInfo( Locale, LOCALE_SMONTHOUSANDSEP, FIELD_OFFSET(NLS_USER_INFO, sMonThouSep), NLS_VALUE_SMONTHOUSANDSEP, pThousand, ARRAYSIZE(pThousand), FALSE ) && IsValidSeparatorString( pThousand, MAX_STHOUSAND, FALSE ) ) { pFormat->lpThousandSep = pThousand; } else { pFormat->lpThousandSep = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SMonThousSep; }
//
// Get the currency symbol.
// This string may be a null string.
//
if ( (!NoUserOverride) && GetUserInfo( Locale, LOCALE_SCURRENCY, FIELD_OFFSET(NLS_USER_INFO, sCurrency), NLS_VALUE_SCURRENCY, pCurrency, ARRAYSIZE(pCurrency), FALSE ) && IsValidSeparatorString( pCurrency, MAX_SCURRENCY, FALSE ) ) { pFormat->lpCurrencySymbol = pCurrency; } else { pFormat->lpCurrencySymbol = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SCurrency; } }
//
// Parse the currency format string.
//
pFinal = pString; Length = ParseCurrency( pHashN, NoUserOverride, (LPWSTR)lpValue, pFormat, &pFinal, MAX_NUMBER_BUFFER, &NeededSizeToAllocate, FALSE );
//
// If the failure is due to a stack variable size limitation, then
// try to satisfy the request from the local process heap.
//
if ((Length == 0) && (NeededSizeToAllocate > 0)) { pTemp = RtlAllocateHeap( RtlProcessHeap(), 0, NeededSizeToAllocate * sizeof(TCHAR) ); if (pTemp) { pFinal = pTemp; Length = ParseCurrency( pHashN, NoUserOverride, (LPWSTR)lpValue, pFormat, &pFinal, NeededSizeToAllocate, &NeededSizeToAllocate, TRUE ); } }
//
// Check cchCurrency for size of given buffer.
//
if ((cchCurrency == 0) || (Length == 0)) { //
// If cchCurrency is 0, then we can't use lpCurrencyStr. In this
// case, we simply want to return the length (in characters) of
// the string to be copied.
//
Length = Length; } else if (cchCurrency < Length) { //
// The buffer is too small for the string, so return an error
// and zero bytes written.
//
SetLastError(ERROR_INSUFFICIENT_BUFFER); Length = 0; } else { //
// Copy the currency string to lpCurrencyStr and null terminate it.
// Return the number of characters copied.
//
if(FAILED(StringCchCopyW(lpCurrencyStr, cchCurrency, pFinal))) { //
// Failure should in theory be impossible, but if we ignore the
// return value, PREfast will complain.
//
SetLastError(ERROR_OUTOFMEMORY); Length = 0; } }
//
// Free any dynamically allocated memory.
//
if (pTemp != NULL) { RtlFreeHeap(RtlProcessHeap(), 0, pTemp); }
//
// Return the number of characters copied.
//
return (Length); }
//-------------------------------------------------------------------------//
// INTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// IsValidNumberFormat
//
// Returns TRUE if the given format is valid. Otherwise, it returns FALSE.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL IsValidNumberFormat( CONST NUMBERFMTW *pFormat)
{ //
// Check for invalid values.
//
if ((pFormat->NumDigits > MAX_VALUE_IDIGITS) || (pFormat->LeadingZero > MAX_VALUE_ILZERO) || (pFormat->Grouping > MAX_GROUPING_NUMBER) || (pFormat->NegativeOrder > MAX_VALUE_INEGNUMBER) || (pFormat->lpDecimalSep == NULL) || (!IsValidSeparatorString( pFormat->lpDecimalSep, MAX_SDECIMAL, (pFormat->NumDigits) ? TRUE : FALSE)) || (pFormat->lpThousandSep == NULL) || (!IsValidSeparatorString( pFormat->lpThousandSep, MAX_STHOUSAND, FALSE ))) { return (FALSE); }
//
// Return success.
//
return (TRUE); }
////////////////////////////////////////////////////////////////////////////
//
// IsValidCurrencyFormat
//
// Returns TRUE if the given format is valid. Otherwise, it returns FALSE.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL IsValidCurrencyFormat( CONST CURRENCYFMTW *pFormat)
{ //
// Check for invalid values.
//
if ((pFormat->NumDigits > MAX_VALUE_IDIGITS) || (pFormat->LeadingZero > MAX_VALUE_ILZERO) || (pFormat->Grouping > MAX_GROUPING_NUMBER) || (pFormat->lpDecimalSep == NULL) || (!IsValidSeparatorString( pFormat->lpDecimalSep, MAX_SMONDECSEP, (pFormat->NumDigits) ? TRUE : FALSE)) || (pFormat->lpThousandSep == NULL) || (!IsValidSeparatorString( pFormat->lpThousandSep, MAX_SMONTHOUSEP, FALSE )) || (pFormat->lpCurrencySymbol == NULL) || (!IsValidSeparatorString( pFormat->lpCurrencySymbol, MAX_SCURRENCY, FALSE )) || (pFormat->PositiveOrder > MAX_VALUE_ICURRENCY) || (pFormat->NegativeOrder > MAX_VALUE_INEGCURR)) { return (FALSE); }
//
// Return success.
//
return (TRUE); }
////////////////////////////////////////////////////////////////////////////
//
// GetRegIntValue
//
// Retrieves the specified locale information, converts the unicode string
// to an integer value, and returns the value.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
UINT GetRegIntValue( LCID Locale, LCTYPE LCType, BOOL NoUserOverride, SIZE_T CacheOffset, LPWSTR pRegVal, LPWSTR pDefault, int DefaultVal, int UpperBound) { UNICODE_STRING ObUnicodeStr; // value string
int Value; // value
WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
//
// Initialize values.
//
Value = -1;
//
// Try the user registry.
//
if ((!NoUserOverride) && GetUserInfo( Locale, LCType, CacheOffset, pRegVal, pTemp, ARRAYSIZE(pTemp), TRUE )) { //
// Convert the user data to an integer.
//
RtlInitUnicodeString(&ObUnicodeStr, pTemp); if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Value)) || (Value < 0) || (Value > UpperBound)) { //
// Bad value, so store -1 so that the system default
// will be used.
//
Value = -1; } }
//
// See if the value obtained above is valid.
//
if (Value < 0) { //
// Convert system default data to an integer.
//
RtlInitUnicodeString(&ObUnicodeStr, pDefault); if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Value)) || (Value < 0) || (Value > UpperBound)) { //
// Bad value, so use the chosen default value.
//
Value = DefaultVal; } }
return ((UINT)Value); }
////////////////////////////////////////////////////////////////////////////
//
// ConvertGroupingStringToInt
//
// Converts the given grouping string to an integer.
// For example, 3;2;0 becomes 32 and 3;0 becomes 3 and 3;2 becomes 320.
//
// NOTE: The pGrouping buffer will be modified.
//
// 01-05-98 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int ConvertGroupingStringToInt( LPWSTR pGroupingSrc, LPWSTR pGroupingDest) { LPWSTR pSrc = pGroupingSrc; // temp ptr to src position
LPWSTR pDest = pGroupingDest; // temp ptr to dest position
UNICODE_STRING ObUnicodeStr; // value string
int Value; // value
//
// Filter out all non-numeric values and all zero values.
// Store the result in the destination buffer.
//
while (*pSrc) { if ((*pSrc < NLS_CHAR_ONE) || (*pSrc > NLS_CHAR_NINE)) { 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 == pGroupingDest) || (*(pSrc - 1) != NLS_CHAR_ZERO)) { *pDest = NLS_CHAR_ZERO; pDest++; }
//
// Null terminate the buffer.
//
*pDest = 0;
//
// Convert the string to an integer.
//
RtlInitUnicodeString(&ObUnicodeStr, pGroupingDest); RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Value);
//
// Return the integer value.
//
return (Value); }
////////////////////////////////////////////////////////////////////////////
//
// GetGroupingValue
//
// Retrieves the specified grouping information, converts the grouping
// string to an integer value (eg. 3;2;0 -> 32), and returns the value.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
UINT GetGroupingValue( LCID Locale, LCTYPE LCType, BOOL NoUserOverride, SIZE_T CacheOffset, LPWSTR pRegVal, LPWSTR pDefault, int DefaultVal) { int Value; // value
WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
//
// Initialize values.
//
Value = -1;
//
// Try the user registry.
//
if ((!NoUserOverride) && GetUserInfo( Locale, LCType, CacheOffset, pRegVal, pTemp, ARRAYSIZE(pTemp), TRUE )) { //
// Convert the grouping string to an integer.
// 3;0 becomes 3, 3;2;0 becomes 32, and 3;2 becomes 320.
//
Value = ConvertGroupingStringToInt(pTemp, pTemp); if (Value < 0) { //
// Bad value, so store -1 so that the system default
// will be used.
//
Value = -1; } }
//
// See if the value obtained above is valid.
//
if (Value < 0) { //
// Convert the grouping string to an integer.
// 3;0 becomes 3, 3;2;0 becomes 32, and 3;2 becomes 320.
//
Value = ConvertGroupingStringToInt(pDefault, pTemp); if (Value < 0) { //
// Bad value, so use the chosen default value.
//
Value = DefaultVal; } }
//
// Return the value.
//
return ((UINT)Value); }
////////////////////////////////////////////////////////////////////////////
//
// GetNumberString
//
// Puts the properly formatted number string into the given string buffer.
// It returns the number of characters written to the string buffer.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int GetNumberString( PLOC_HASH pHashN, LPWSTR pValue, LPNUMBERFMTW pFormat, LPWSTR *ppBuf, int BufSize, BOOL *pfZeroValue, int *pNeededSizeToAllocate, BOOL fSetError)
{ LPWSTR pDecPt; // ptr to decimal point in given buffer
LPWSTR pPos; // ptr to position in given buffer
LPWSTR pPos2; // ptr to position in given buffer
LPWSTR pPosBuf; // ptr to position in final buffer
int IntPartSize; // size of integer part of string
int GroupSize; // size of groupings left of decimal
int IntegerNum; // number of integers left of decimal
WCHAR wch; // wide character place holder
int pGroupArray[MAX_GROUPS]; // array of groups
int NumGroupings; // number of groupings
int NumSeparators; // number of separators
int NumDigits; // number of digits
int Ctr; // loop counter
UINT NumRound = 1; // # digits left before adding group separator
//
// Reset to indicate no need to allocate memory dynamically.
//
*pNeededSizeToAllocate = 0;
//
// Validate the string and find the decimal point in the string.
//
// The only valid characters within the string are:
// negative sign - in first position only
// decimal point
// Unicode code points for integers 0 - 9
//
pPos = pValue; while ((wch = *pPos) && (wch != NLS_CHAR_PERIOD)) { if ((wch < NLS_CHAR_ZERO) || (wch > NLS_CHAR_NINE)) { SetLastError(ERROR_INVALID_PARAMETER); return (0); } pPos++; } pDecPt = pPos;
if (*pPos) { pPos++; while (wch = *pPos) { if ((wch < NLS_CHAR_ZERO) || (wch > NLS_CHAR_NINE)) { SetLastError(ERROR_INVALID_PARAMETER); return (0); } pPos++; } }
//
// Remove any leading zeros in the integer part.
//
while (pValue < pDecPt) { if (*pValue != NLS_CHAR_ZERO) { break; } pValue++; }
//
// Save the number of integers to the left of the decimal.
//
IntegerNum = (int)(pDecPt - pValue);
//
// Make sure the value string passed in is not too large for
// the buffers.
//
IntPartSize = IntegerNum; NumGroupings = 0; NumSeparators = 0; if ((GroupSize = pFormat->Grouping) && (IntPartSize)) { //
// Count the number of groupings and save them in an array to be
// used later.
//
while (GroupSize && (NumGroupings < MAX_GROUPS)) { pGroupArray[NumGroupings] = GroupSize % 10; GroupSize /= 10; NumGroupings++; }
//
// Count the number of groupings that apply to the given number
// string.
//
NumDigits = IntegerNum; Ctr = (NumGroupings != 0) ? (NumGroupings - 1) : 0; while (Ctr) { if (NumDigits > pGroupArray[Ctr]) { NumDigits -= pGroupArray[Ctr]; NumSeparators++; } else { if (NumDigits == pGroupArray[Ctr]) { NumRound = 0; } break; } Ctr--; } if ((Ctr == 0) && pGroupArray[0]) { if (NumDigits > pGroupArray[0]) { NumSeparators += (NumDigits - 1) / pGroupArray[0]; } NumRound = NumDigits % pGroupArray[0]; }
IntPartSize += MAX_STHOUSAND * NumSeparators; }
//
// Make sure the buffer is large enough. If not, return the size
// needed.
//
if (IntPartSize > (BufSize - MAX_NON_INTEGER_PART)) { if (fSetError) { SetLastError(ERROR_INVALID_PARAMETER); } *pNeededSizeToAllocate = (IntPartSize + MAX_NON_INTEGER_PART); return (0); }
//
// Initialize pointers.
//
pPosBuf = *ppBuf; pPos = pValue; *pfZeroValue = FALSE;
//
// See if there are any digits before the decimal point.
//
if (pPos == pDecPt) { //
// Possibly a zero value. All leading zeros were removed, so
// there is no integer part.
//
*pfZeroValue = TRUE;
//
// No digits before decimal point, so add a leading zero
// to the final string if appropriate.
//
if (pFormat->LeadingZero) { *pPosBuf = NLS_CHAR_ZERO; pPosBuf++; } } else if (!NumSeparators) { //
// Grouping Size is zero or larger than the integer part of the
// string, so copy up to the decimal point (or end of string).
//
while (pPos < pDecPt) { *pPosBuf = *pPos; pPosBuf++; pPos++; } } else { //
// Copy up to where the first thousand separator should be.
// Use groupings of GroupSize numbers up to the decimal point.
//
NumDigits = IntegerNum; Ctr = (NumGroupings != 0) ? (NumGroupings - 1) : 0; while (Ctr) { if (NumDigits > pGroupArray[Ctr]) { NumDigits -= pGroupArray[Ctr]; } else { break; } Ctr--; } GroupSize = pGroupArray[Ctr];
pPos2 = GroupSize ? (pPos + (NumDigits % GroupSize)) : (pPos + NumDigits); if (pPos2 == pPos) { //
// Don't want to write thousand separator at the beginning
// of the string. There's at least GroupSize numbers
// in the string, so just advance pPos2 so that GroupSize
// numbers will be copied.
//
pPos2 = pPos + GroupSize; } while (pPos < pPos2) { *pPosBuf = *pPos; pPosBuf++; pPos++; NumDigits--; }
//
// Copy the thousand separator followed by GroupSize number of
// digits from the given string until the entire repeating
// GroupSize ends (or end of string).
//
while (NumDigits) { //
// Copy the localized thousand separator.
//
pPos2 = pFormat->lpThousandSep; while (*pPos2) { *pPosBuf = *pPos2; pPosBuf++; pPos2++; }
//
// Copy GroupSize number of digits.
//
pPos2 = pPos + GroupSize; while (pPos < pPos2) { *pPosBuf = *pPos; pPosBuf++; pPos++; NumDigits--; } }
//
// Copy the thousand separator followed by GroupSize number of
// digits from the given string - until the decimal point (or
// end of string) in the given string is reached.
//
if (pPos < pDecPt) { Ctr++; while (Ctr < NumGroupings) { //
// Copy the localized thousand separator.
//
pPos2 = pFormat->lpThousandSep; while (*pPos2) { *pPosBuf = *pPos2; pPosBuf++; pPos2++; }
//
// Copy GroupSize number of digits.
//
pPos2 = pPos + pGroupArray[Ctr]; while (pPos < pPos2) { *pPosBuf = *pPos; pPosBuf++; pPos++; }
//
// Go to the next grouping.
//
Ctr++; } } }
//
// See if there is a decimal separator in the given string.
//
if (pFormat->NumDigits > 0) { //
// Copy the localized decimal separator only if the number
// of digits right of the decimal is greater than zero.
//
pDecPt = pPosBuf; pPos2 = pFormat->lpDecimalSep; while (*pPos2) { *pPosBuf = *pPos2; pPosBuf++; pPos2++; } }
//
// Skip over the decimal point in the given string and
// copy the rest of the digits from the given string.
//
if (*pPos) { pPos++; } pPos2 = pPos + pFormat->NumDigits; while ((*pPos) && (pPos < pPos2)) { if (*pPos != NLS_CHAR_ZERO) { *pfZeroValue = FALSE; } *pPosBuf = *pPos; pPosBuf++; pPos++; }
//
// Make sure some value is in the buffer.
//
if (*ppBuf == pPosBuf) { *pPosBuf = NLS_CHAR_ZERO; pPosBuf++; }
//
// See if we need to round the number or pad it with zeros.
//
if (*pPos) { //
// Round the number if necessary.
//
if (*pPos2 > L'4') { *pfZeroValue = FALSE;
//
// Round the number. If GroupSize is 0, then we need to
// pass in a non-zero value so that the thousand separator
// will not be added to the front of the string (if it
// rounds that far).
//
pPosBuf--; NLS_ROUND_IT( *ppBuf, pPosBuf, NumRound, pFormat->lpThousandSep ); pPosBuf++; } } else { //
// Pad the string with the appropriate number of zeros.
//
while (pPos < pPos2) { *pPosBuf = NLS_CHAR_ZERO; pPosBuf++; pPos++; } }
//
// Zero terminate the string.
//
*pPosBuf = 0;
//
// Return the number of characters written to the buffer, including
// the null terminator.
//
return ((int)((pPosBuf - *ppBuf) + 1)); }
////////////////////////////////////////////////////////////////////////////
//
// ParseNumber
//
// Puts the properly formatted number string into the given string buffer.
// It returns the number of characters written to the string buffer.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int ParseNumber( PLOC_HASH pHashN, BOOL NoUserOverride, LPWSTR pValue, LPNUMBERFMTW pFormat, LPWSTR *ppBuf, int BufSize, int *pNeededSizeToAllocate, BOOL fSetError)
{ LPWSTR pBegin; // ptr to beginning of final buffer
LPWSTR pEnd; // ptr to end of final buffer
LPWSTR pNegSign; // ptr to negative sign string
BOOL IsNeg; // if negative sign in string
int Length; // length of number string
BOOL fZeroValue = FALSE; // if number is a zero value
int NegSignSize; // size of negative sign string
WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
//
// Initialize pointer.
//
// Account for:
// - negative sign
// - blank spaces
// - one extra number from rounding
// - one extra grouping separator from rounding
//
pBegin = *ppBuf + MAX_NUMBER_EXTRAS;
//
// If the first value is a negative, then increment past it.
//
if (IsNeg = (*pValue == NLS_CHAR_HYPHEN)) { pValue++; }
//
// Get the appropriate number string and place it in the buffer.
//
Length = GetNumberString( pHashN, pValue, pFormat, &pBegin, BufSize - MAX_NUMBER_EXTRAS, &fZeroValue, pNeededSizeToAllocate, fSetError ); if (!Length) { if (*pNeededSizeToAllocate > 0) { *pNeededSizeToAllocate += MAX_NUMBER_EXTRAS; } return (0); }
//
// Advance pEnd position pointer to the end of the number string.
//
pEnd = pBegin + (Length - 1);
//
// See if any characters should be put in the buffer BEFORE and
// AFTER the properly formatted number string.
// - negative sign or opening/closing parenthesis
// - blank space
//
if (!fZeroValue && IsNeg) { //
// Get the negative sign string.
//
if (pFormat->NegativeOrder != 0) { if ( (!NoUserOverride) && GetUserInfo( pHashN->Locale, LOCALE_SNEGATIVESIGN, FIELD_OFFSET(NLS_USER_INFO, sNegSign), NLS_VALUE_SNEGATIVESIGN, pTemp, ARRAYSIZE(pTemp), TRUE ) && IsValidSeparatorString( pTemp, MAX_SNEGSIGN, FALSE ) ) { pNegSign = pTemp; } else { pNegSign = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SNegativeSign; } }
switch (pFormat->NegativeOrder) { case ( 0 ) : { //
// Put the opening parenthesis in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_OPEN_PAREN;
//
// Put the closing parenthesis in the buffer.
//
*pEnd = NLS_CHAR_CLOSE_PAREN; pEnd++;
break; } case ( 2 ) : { //
// Put the space in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_SPACE;
//
// Fall through to case 1.
//
} case ( 1 ) : default : { //
// Copy the negative sign to the buffer.
//
NegSignSize = NlsStrLenW(pNegSign); pBegin -= NegSignSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pNegSign);
break; } case ( 4 ) : { //
// Put the space in the buffer.
//
*pEnd = NLS_CHAR_SPACE; pEnd++;
//
// Fall Through to case 3.
//
} case ( 3 ) : { //
// Copy the negative sign to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pNegSign);
break; } } }
//
// Zero terminate the string.
//
*pEnd = 0;
//
// Return the pointer to the beginning of the string.
//
*ppBuf = pBegin;
//
// Return the number of characters written to the buffer, including
// the null terminator.
//
return ((int)((pEnd - pBegin) + 1)); }
////////////////////////////////////////////////////////////////////////////
//
// ParseCurrency
//
// Puts the properly formatted currency string into the given string buffer.
// It returns the number of characters written to the string buffer.
//
// 07-28-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int ParseCurrency( PLOC_HASH pHashN, BOOL NoUserOverride, LPWSTR pValue, LPCURRENCYFMTW pFormat, LPWSTR *ppBuf, int BufSize, int *pNeededSizeToAllocate, BOOL fSetError)
{ LPWSTR pBegin; // ptr to beginning of final buffer
LPWSTR pEnd; // ptr to end of final buffer
LPWSTR pNegSign; // ptr to negative sign string
BOOL IsNeg; // if negative sign in string
int Length; // length of number string
BOOL fZeroValue = FALSE; // if number is a zero value
int NegSignSize; // size of negative sign string
UINT NegOrder; // negative ordering
int CurrSymSize; // size of currency symbol
WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
//
// Initialize pointer.
//
// Account for:
// - negative sign
// - currency sign
// - blank spaces
// - one extra number from rounding
// - one extra grouping separator from rounding
//
pBegin = *ppBuf + MAX_CURRENCY_EXTRAS;
//
// If the first value is a negative, then increment past it.
//
if (IsNeg = (*pValue == NLS_CHAR_HYPHEN)) { pValue++; }
//
// Get the appropriate number string and place it in the buffer.
//
Length = GetNumberString( pHashN, pValue, (LPNUMBERFMTW)pFormat, &pBegin, BufSize - MAX_CURRENCY_EXTRAS, &fZeroValue, pNeededSizeToAllocate, fSetError ); if (!Length) { if (*pNeededSizeToAllocate > 0) { *pNeededSizeToAllocate += MAX_CURRENCY_EXTRAS; } return (0); }
//
// Advance pEnd position pointer to the end of the number string.
//
pEnd = pBegin + (Length - 1);
//
// Get the size of the currency symbol.
//
CurrSymSize = NlsStrLenW(pFormat->lpCurrencySymbol);
//
// See if any characters should be put in the buffer BEFORE and
// AFTER the properly formatted number string.
// - currency symbol
// - negative sign or opening/closing parenthesis
// - blank space
//
if (!fZeroValue && IsNeg) { //
// Get the negative sign string and the size of it.
//
NegOrder = pFormat->NegativeOrder; if ((NegOrder != 0) && (NegOrder != 4) && (NegOrder < 14)) { if ( (!NoUserOverride) && GetUserInfo( pHashN->Locale, LOCALE_SNEGATIVESIGN, FIELD_OFFSET(NLS_USER_INFO, sNegSign), NLS_VALUE_SNEGATIVESIGN, pTemp, ARRAYSIZE(pTemp), TRUE ) && IsValidSeparatorString( pTemp, MAX_SNEGSIGN, FALSE ) ) { pNegSign = pTemp; } else { pNegSign = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SNegativeSign; }
NegSignSize = NlsStrLenW(pNegSign); }
switch (NegOrder) { case ( 0 ) : { //
// Copy the currency symbol to the buffer.
//
pBegin -= CurrSymSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pFormat->lpCurrencySymbol);
//
// Put the opening parenthesis in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_OPEN_PAREN;
//
// Put the closing parenthesis in the buffer.
//
*pEnd = NLS_CHAR_CLOSE_PAREN; pEnd++;
break; } case ( 1 ) : default : { //
// Copy the currency symbol to the buffer.
//
pBegin -= CurrSymSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pFormat->lpCurrencySymbol);
//
// Copy the negative sign to the buffer.
//
pBegin -= NegSignSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pNegSign);
break; } case ( 2 ) : { //
// Copy the negative sign to the buffer.
//
pBegin -= NegSignSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pNegSign);
//
// Copy the currency symbol to the buffer.
//
pBegin -= CurrSymSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pFormat->lpCurrencySymbol);
break; } case ( 3 ) : { //
// Copy the currency symbol to the buffer.
//
pBegin -= CurrSymSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pFormat->lpCurrencySymbol);
//
// Copy the negative sign to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pNegSign);
break; } case ( 4 ) : { //
// Put the opening parenthesis in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_OPEN_PAREN;
//
// Copy the currency symbol to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pFormat->lpCurrencySymbol);
//
// Put the closing parenthesis in the buffer.
//
*pEnd = NLS_CHAR_CLOSE_PAREN; pEnd++;
break; } case ( 5 ) : { //
// Copy the negative sign to the buffer.
//
pBegin -= NegSignSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pNegSign);
//
// Copy the currency symbol to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pFormat->lpCurrencySymbol);
break; } case ( 6 ) : { //
// Copy the negative sign to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pNegSign);
//
// Copy the currency symbol to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pFormat->lpCurrencySymbol);
break; } case ( 7 ) : { //
// Copy the currency symbol to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pFormat->lpCurrencySymbol);
//
// Copy the negative sign to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pNegSign);
break; } case ( 8 ) : { //
// Copy the negative sign to the buffer.
//
pBegin -= NegSignSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pNegSign);
//
// Put a space in the buffer.
//
*pEnd = NLS_CHAR_SPACE; pEnd++;
//
// Copy the currency symbol to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pFormat->lpCurrencySymbol);
break; } case ( 9 ) : { //
// Put a space in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_SPACE;
//
// Copy the currency symbol to the buffer.
//
pBegin -= CurrSymSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pFormat->lpCurrencySymbol);
//
// Copy the negative sign to the buffer.
//
pBegin -= NegSignSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pNegSign);
break; } case ( 10 ) : { //
// Put a space in the buffer.
//
*pEnd = NLS_CHAR_SPACE; pEnd++;
//
// Copy the currency symbol to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pFormat->lpCurrencySymbol);
//
// Copy the negative sign to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pNegSign);
break; } case ( 11 ) : { //
// Put a space in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_SPACE;
//
// Copy the currency symbol to the buffer.
//
pBegin -= CurrSymSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pFormat->lpCurrencySymbol);
//
// Copy the negative sign to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pNegSign);
break; } case ( 12 ) : { //
// Copy the negative sign to the buffer.
//
pBegin -= NegSignSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pNegSign);
//
// Put a space in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_SPACE;
//
// Copy the currency symbol to the buffer.
//
pBegin -= CurrSymSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pFormat->lpCurrencySymbol);
break; } case ( 13 ) : { //
// Copy the negative sign to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pNegSign);
//
// Put a space in the buffer.
//
*pEnd = NLS_CHAR_SPACE; pEnd++;
//
// Copy the currency symbol to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pFormat->lpCurrencySymbol);
break; } case ( 14 ) : { //
// Put a space in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_SPACE;
//
// Copy the currency symbol to the buffer.
//
pBegin -= CurrSymSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pFormat->lpCurrencySymbol);
//
// Put the opening parenthesis in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_OPEN_PAREN;
//
// Put the closing parenthesis in the buffer.
//
*pEnd = NLS_CHAR_CLOSE_PAREN; pEnd++;
break; } case ( 15 ) : { //
// Put the opening parenthesis in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_OPEN_PAREN;
//
// Put a space in the buffer.
//
*pEnd = NLS_CHAR_SPACE; pEnd++;
//
// Copy the currency symbol to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pFormat->lpCurrencySymbol);
//
// Put the closing parenthesis in the buffer.
//
*pEnd = NLS_CHAR_CLOSE_PAREN; pEnd++;
break; } } } else { //
// Positive value. Store the currency symbol in the string
// if the positive order is either 0 or 2. Otherwise, wait
// till the end.
//
switch (pFormat->PositiveOrder) { case ( 2 ) : { //
// Put a space in the buffer.
//
pBegin--; *pBegin = NLS_CHAR_SPACE;
//
// Fall through to case 0.
//
} case ( 0 ) : default : { //
// Copy the currency symbol to the buffer.
//
pBegin -= CurrSymSize; NLS_COPY_UNICODE_STR_TMP(pBegin, pFormat->lpCurrencySymbol);
break; } case ( 3 ) : { //
// Put a space in the buffer.
//
*pEnd = NLS_CHAR_SPACE; pEnd++;
//
// Fall through to case 1.
//
} case ( 1 ) : { //
// Copy the currency symbol to the buffer.
//
NLS_COPY_UNICODE_STR(pEnd, pFormat->lpCurrencySymbol);
break; } } }
//
// Zero terminate the string.
//
*pEnd = 0;
//
// Return the pointer to the beginning of the string.
//
*ppBuf = pBegin;
//
// Return the number of characters written to the buffer, including
// the null terminator.
//
return ((int)((pEnd - pBegin) + 1)); }
|