mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1954 lines
57 KiB
1954 lines
57 KiB
/*++
|
|
|
|
Copyright (c) 1991-1996, 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"
|
|
|
|
|
|
|
|
|
|
//
|
|
// Constant Declarations.
|
|
//
|
|
|
|
#define MAX_NUMBER_BUFFER 256 // max size of buffer
|
|
#define MAX_INTEGER_PART ( MAX_NUMBER_BUFFER - \
|
|
( MAX_VALUE_IDIGITS + \
|
|
MAX_SDECIMAL + \
|
|
MAX_SNEGSIGN + 1 ) )
|
|
|
|
|
|
|
|
|
|
//
|
|
// Forward Declarations.
|
|
//
|
|
|
|
BOOL
|
|
IsValidNumberFormat(
|
|
CONST NUMBERFMTW *pFormat);
|
|
|
|
BOOL
|
|
IsValidCurrencyFormat(
|
|
CONST CURRENCYFMTW *pFormat);
|
|
|
|
UINT
|
|
GetRegIntValue(
|
|
LCID Locale,
|
|
BOOL NoUserOverride,
|
|
LPWSTR pRegVal,
|
|
LPWSTR pDefault,
|
|
int DefaultVal,
|
|
int UpperBound);
|
|
|
|
UINT
|
|
GetGroupingValue(
|
|
LCID Locale,
|
|
BOOL NoUserOverride,
|
|
LPWSTR pRegVal,
|
|
LPWSTR pDefault,
|
|
int DefaultVal,
|
|
int UpperBound);
|
|
|
|
int
|
|
GetNumberString(
|
|
PLOC_HASH pHashN,
|
|
LPWSTR pValue,
|
|
LPNUMBERFMTW pFormat,
|
|
LPWSTR *ppBuf,
|
|
BOOL *pfZeroValue);
|
|
|
|
int
|
|
ParseNumber(
|
|
PLOC_HASH pHashN,
|
|
BOOL NoUserOverride,
|
|
LPWSTR pValue,
|
|
LPNUMBERFMTW pFormat,
|
|
LPWSTR *ppBuf);
|
|
|
|
int
|
|
ParseCurrency(
|
|
PLOC_HASH pHashN,
|
|
BOOL NoUserOverride,
|
|
LPWSTR pValue,
|
|
LPCURRENCYFMTW pFormat,
|
|
LPWSTR *ppBuf);
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------//
|
|
// 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) = L'1'; \
|
|
} \
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------//
|
|
// 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
|
|
|
|
|
|
//
|
|
// Initialize UserOverride.
|
|
//
|
|
NoUserOverride = dwFlags & LOCALE_NOUSEROVERRIDE;
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - validate LCID
|
|
// - count is negative
|
|
// - NULL data pointer AND count is not zero
|
|
// - ptrs to string buffers same
|
|
//
|
|
VALIDATE_LOCALE(Locale, pHashN);
|
|
if ( (pHashN == NULL) ||
|
|
(cchNumber < 0) ||
|
|
((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,
|
|
NoUserOverride,
|
|
pNlsUserInfo->iDigits,
|
|
pHashN->pLocaleFixed->szIDigits,
|
|
2,
|
|
MAX_VALUE_IDIGITS );
|
|
|
|
//
|
|
// Get the leading zero in decimal fields option.
|
|
//
|
|
pFormat->LeadingZero =
|
|
GetRegIntValue( Locale,
|
|
NoUserOverride,
|
|
pNlsUserInfo->iLZero,
|
|
pHashN->pLocaleFixed->szILZero,
|
|
1,
|
|
MAX_VALUE_ILZERO );
|
|
|
|
//
|
|
// Get the negative ordering.
|
|
//
|
|
pFormat->NegativeOrder =
|
|
GetRegIntValue( Locale,
|
|
NoUserOverride,
|
|
pNlsUserInfo->iNegNumber,
|
|
pHashN->pLocaleFixed->szINegNumber,
|
|
1,
|
|
MAX_VALUE_INEGNUMBER );
|
|
|
|
//
|
|
// Get the grouping left of the decimal.
|
|
//
|
|
pFormat->Grouping =
|
|
GetGroupingValue( Locale,
|
|
NoUserOverride,
|
|
pNlsUserInfo->sGrouping,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->SGrouping,
|
|
3,
|
|
MAX_VALUE_SGROUPING );
|
|
|
|
//
|
|
// Get the decimal separator.
|
|
//
|
|
// NOTE: This must follow the above calls because
|
|
// pDecSep is used as a temporary buffer above.
|
|
//
|
|
if ( (!NoUserOverride) &&
|
|
GetUserInfo( Locale,
|
|
pNlsUserInfo->sDecimal,
|
|
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,
|
|
pNlsUserInfo->sThousand,
|
|
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 );
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
return (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);
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// Copy the number string to lpNumberStr and null terminate it.
|
|
// Return the number of characters copied.
|
|
//
|
|
NlsStrCpyW(lpNumberStr, pFinal);
|
|
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
|
|
|
|
|
|
//
|
|
// Initialize UserOverride.
|
|
//
|
|
NoUserOverride = dwFlags & LOCALE_NOUSEROVERRIDE;
|
|
|
|
//
|
|
// Invalid Parameter Check:
|
|
// - validate LCID
|
|
// - count is negative
|
|
// - NULL data pointer AND count is not zero
|
|
// - ptrs to string buffers same
|
|
//
|
|
VALIDATE_LOCALE(Locale, pHashN);
|
|
if ( (pHashN == NULL) ||
|
|
(cchCurrency < 0) ||
|
|
((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,
|
|
NoUserOverride,
|
|
pNlsUserInfo->iCurrDigits,
|
|
pHashN->pLocaleFixed->szICurrDigits,
|
|
2,
|
|
MAX_VALUE_ICURRDIGITS );
|
|
|
|
//
|
|
// Get the leading zero in decimal fields option.
|
|
//
|
|
pFormat->LeadingZero =
|
|
GetRegIntValue( Locale,
|
|
NoUserOverride,
|
|
pNlsUserInfo->iLZero,
|
|
pHashN->pLocaleFixed->szILZero,
|
|
1,
|
|
MAX_VALUE_ILZERO );
|
|
|
|
//
|
|
// Get the positive ordering.
|
|
//
|
|
pFormat->PositiveOrder =
|
|
GetRegIntValue( Locale,
|
|
NoUserOverride,
|
|
pNlsUserInfo->iCurrency,
|
|
pHashN->pLocaleFixed->szICurrency,
|
|
0,
|
|
MAX_VALUE_ICURRENCY );
|
|
|
|
//
|
|
// Get the negative ordering.
|
|
//
|
|
pFormat->NegativeOrder =
|
|
GetRegIntValue( Locale,
|
|
NoUserOverride,
|
|
pNlsUserInfo->iNegCurr,
|
|
pHashN->pLocaleFixed->szINegCurr,
|
|
1,
|
|
MAX_VALUE_INEGCURR );
|
|
|
|
//
|
|
// Get the grouping left of the decimal.
|
|
//
|
|
pFormat->Grouping =
|
|
GetGroupingValue( Locale,
|
|
NoUserOverride,
|
|
pNlsUserInfo->sMonGrouping,
|
|
(LPWORD)(pHashN->pLocaleHdr) +
|
|
pHashN->pLocaleHdr->SMonGrouping,
|
|
3,
|
|
MAX_VALUE_SMONGROUPING );
|
|
|
|
//
|
|
// Get the decimal separator.
|
|
//
|
|
// NOTE: This must follow the above calls because
|
|
// pDecSep is used as a temporary buffer.
|
|
//
|
|
if ( (!NoUserOverride) &&
|
|
GetUserInfo( Locale,
|
|
pNlsUserInfo->sMonDecSep,
|
|
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,
|
|
pNlsUserInfo->sMonThouSep,
|
|
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,
|
|
pNlsUserInfo->sCurrency,
|
|
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 );
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
return (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);
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// Copy the currency string to lpCurrencyStr and null terminate it.
|
|
// Return the number of characters copied.
|
|
//
|
|
NlsStrCpyW(lpCurrencyStr, pFinal);
|
|
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_VALUE_SGROUPING ) ||
|
|
( 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_VALUE_SGROUPING ) ||
|
|
( 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,
|
|
BOOL NoUserOverride,
|
|
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,
|
|
pRegVal,
|
|
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);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetGroupingValue
|
|
//
|
|
// Retrieves the specified grouping information, uses only the first digit
|
|
// to convert it to an integer value, and returns the value.
|
|
//
|
|
// 07-28-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
UINT GetGroupingValue(
|
|
LCID Locale,
|
|
BOOL NoUserOverride,
|
|
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,
|
|
pRegVal,
|
|
pTemp,
|
|
TRUE ))
|
|
{
|
|
//
|
|
// Only use the first integer value, so null terminate it
|
|
// after the first character. Must do this in a temp buffer.
|
|
//
|
|
*(pTemp + 1) = 0;
|
|
|
|
//
|
|
// 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)
|
|
{
|
|
//
|
|
// Store the default value in a temp buffer.
|
|
//
|
|
*pTemp = *(pDefault);
|
|
*(pTemp + 1) = 0;
|
|
|
|
//
|
|
// Convert system default data to an integer.
|
|
//
|
|
RtlInitUnicodeString(&ObUnicodeStr, pTemp);
|
|
if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Value)) ||
|
|
(Value < 0) || (Value > UpperBound))
|
|
{
|
|
//
|
|
// Bad value, so use the chosen default value.
|
|
//
|
|
Value = DefaultVal;
|
|
}
|
|
}
|
|
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,
|
|
BOOL *pfZeroValue)
|
|
|
|
{
|
|
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
|
|
|
|
|
|
//
|
|
// 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 = pDecPt - pValue;
|
|
|
|
//
|
|
// Make sure the value string passed in is not too large for
|
|
// the buffers.
|
|
//
|
|
IntPartSize = IntegerNum;
|
|
if ((GroupSize = pFormat->Grouping) && (IntPartSize))
|
|
{
|
|
IntPartSize += MAX_STHOUSAND * ((IntPartSize - 1) / GroupSize);
|
|
}
|
|
if (IntPartSize > MAX_INTEGER_PART)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
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 ((!GroupSize) || (GroupSize >= IntegerNum))
|
|
{
|
|
//
|
|
// 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.
|
|
//
|
|
pPos2 = pPos + (IntegerNum % GroupSize);
|
|
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++;
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
while (pPos < pDecPt)
|
|
{
|
|
//
|
|
// 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++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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,
|
|
( (GroupSize && IntegerNum)
|
|
? (IntegerNum % GroupSize)
|
|
: 1 ),
|
|
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 ((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)
|
|
|
|
{
|
|
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; // 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_SNEGSIGN + MAX_BLANKS + 1 + MAX_SGROUPING;
|
|
|
|
//
|
|
// 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,
|
|
&fZeroValue );
|
|
if (!Length)
|
|
{
|
|
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,
|
|
pNlsUserInfo->sNegSign,
|
|
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 ((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)
|
|
|
|
{
|
|
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; // 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_SNEGSIGN + MAX_SCURRENCY + MAX_BLANKS + 1 + MAX_SGROUPING;
|
|
|
|
//
|
|
// 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,
|
|
&fZeroValue );
|
|
if (!Length)
|
|
{
|
|
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,
|
|
pNlsUserInfo->sNegSign,
|
|
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 ((pEnd - pBegin) + 1);
|
|
}
|
|
|
|
|