windows-nt/Source/XPSP1/NT/net/mmc/common/intlnum.cpp
2020-09-26 16:20:57 +08:00

373 lines
8.1 KiB
C++

/**********************************************************************/
/** Microsoft Windows/NT **/
/** Copyright(c) Microsoft Corporation, 1995 - 1997 **/
/**********************************************************************/
/*
FILE HISTORY:
*/
#define OEMRESOURCE
#include "stdafx.h"
#include <stdlib.h>
#include <memory.h>
#include <ctype.h>
#include "objplus.h"
#include "intlnum.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
//
// Initialise static thousand seperator string
//
CString CIntlNumber::m_strThousandSeperator(GetThousandSeperator());
CString CIntlNumber::m_strBadNumber("--");
/***
*
* CIntlNumber::GetThousandSeperator
*
* Purpose:
*
* Get the thousand seperator string from the registry (win32) or the
* win.ini file (win16).
*
* Returns:
*
* A CString containing the system thousand seperator, or the
* American default (",") in case of failure.
*
*/
CString CIntlNumber::GetThousandSeperator()
{
#define MAXLEN 6
#ifdef _WIN32
CString str;
if (::GetLocaleInfo(GetUserDefaultLCID(), LOCALE_STHOUSAND, str.GetBuffer(MAXLEN), MAXLEN))
{
str.ReleaseBuffer();
return(str);
}
Trace0("Couldn't get 1000 seperator from system, using american default");
str = ",";
return(str);
#endif // _WIN32
#ifdef _WIN16
CString str;
::GetProfileString("Intl", "sThousand", ",", str.GetBuffer(MAXLEN), MAXLEN);
str.ReleaseBuffer();
return(str);
#endif // _WIN16
}
/***
*
* CIntlNumber::Reset()
*
* Purpose:
*
* Reset the international settings. Usually in response to
* a change in those international settings by the user.
*
* Notes:
*
* This is a publically available static function.
*
*/
void CIntlNumber::Reset()
{
CIntlNumber::m_strThousandSeperator = GetThousandSeperator();
}
/***
*
* CIntlNumber::ConvertNumberToString
*
* Purpose:
*
* Convert the given long number to a string, inserting thousand
* seperators at the appropriate intervals.
*
* Arguments:
*
* const LONG l The number to convert
*
* Returns:
*
* A CString containing the number in string format.
*
*/
CString CIntlNumber::ConvertNumberToString(const LONG l)
{
// Default returned string:
CString str = CIntlNumber::m_strBadNumber;
LPTSTR lpOutString = str.GetBuffer(16);
int outstrlen;
// Forget about the negative sign for now.
LONG lNum = (l >= 0) ? l : -l;
outstrlen = 0;
do
{
lpOutString[outstrlen++] = '0' + (TCHAR)(lNum % 10);
lNum /= 10;
// if more digits left and we're on a 1000 boundary (printed 3 digits,
// or 3 digits + n*(3 digits + 1 comma), then print a 1000 separator.
if (lNum != 0 && (outstrlen == 3 || outstrlen == 7 || outstrlen == 11))
{
lstrcpy (lpOutString + outstrlen, CIntlNumber::m_strThousandSeperator);
outstrlen += m_strThousandSeperator.GetLength();
}
} while (lNum > 0);
// Add a negative sign if necessary.
if (l < 0L)
{
lpOutString[outstrlen++] = '-';
}
lpOutString[outstrlen] = '\0';
str.ReleaseBuffer();
str.MakeReverse();
return(str);
}
/***
*
* CIntlNumber::ConvertStringToNumber
*
* Purpose:
*
* Given a CString, with optional thousand seperators, convert it to
* a LONG.
*
* Arguments:
*
* const CString & str The string to convert
* BOOL * pfOk Returns TRUE for successful conversion,
* FALSE for failure.
*
* Returns:
*
* The return value is the number, or 0 if the string contained
* invalid characters.
*
* Notes:
*
* If a negative sign is given, it must be the first character of
* the string, immediately (no spaces) followed by the number.
*
* Optional thousand seperators can only be placed at the expected
* 3 digit intervals. The function will return an error if a thousand
* seperator is encountered elsewhere.
*
* [CAVEAT] This function will not accept thousand seperators of longer
* than one character.
*
* No leading or trailing spaces will be acceptable.
*
*/
LONG CIntlNumber::ConvertStringToNumber(const CString & str, BOOL * pfOk)
{
CString strNumber(str);
LONG lValue = 0L;
LONG lBase = 1L;
*pfOk = FALSE;
BOOL fNegative = FALSE;
// Empty strings are invalid
if (strNumber.IsEmpty())
{
return(lValue);
}
int i;
strNumber.MakeReverse();
for (i=0; i<strNumber.GetLength(); ++i)
{
if ((strNumber[i] >= '0') && (strNumber[i] <= '9'))
{
lValue += (LONG)(strNumber[i] - '0') * lBase;
lBase *= 10;
}
// It's not a digit, maybe a thousand seperator?
// CAVEAT: If a thousand seperator of more than
// one character is used, this won't work.
else if ((strNumber[i] != m_strThousandSeperator[0]) ||
(i != 3) && (i != 7) && (i != 11))
{
// Check for negative sign (at the end only)
if ((strNumber[i] == '-') && (i == strNumber.GetLength()-1))
{
fNegative = TRUE;
}
else
{
// This is just invalid, since it is not a thousand
// seperator in the proper location, nor a negative
// sign.
Trace1("Invalid character %c encountered in numeric conversion", (BYTE)strNumber[i]);
return(0L);
}
}
}
if (fNegative)
{
lValue = -lValue;
}
*pfOk = TRUE;
return (lValue);
}
// Constructor taking a CString argument
CIntlNumber::CIntlNumber(const CString & str)
{
m_lValue = ConvertStringToNumber(str, &m_fInitOk);
}
// Assignment operator
CIntlNumber & CIntlNumber::operator =(LONG l)
{
m_lValue = l;
m_fInitOk = TRUE;
return(*this);
}
// Assignment operator
CIntlNumber & CIntlNumber::operator =(const CString &str)
{
m_lValue = ConvertStringToNumber(str, &m_fInitOk);
return(*this);
}
// Conversion operator
CIntlNumber::operator const CString() const
{
return(IsValid() ? ConvertNumberToString(m_lValue) : CIntlNumber::m_strBadNumber);
}
#ifdef _DEBUG
//
// Dump context to the debugging output
//
CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CIntlNumber& num)
{
dc << num.m_lValue;
return(dc);
}
#endif // _DEBUG
// Initialise static thousand seperator string
CString CIntlLargeNumber::m_strBadNumber("--");
/***
*
* CIntlLargeNumber::ConvertNumberToString
*
* Purpose:
*
* Convert the given long number to a string.
*
* Returns:
*
* A CString containing the number in string format.
*
*/
CString CIntlLargeNumber::ConvertNumberToString()
{
CString str;
TCHAR sz[20];
TCHAR *pch = sz;
::wsprintf(sz, _T("%08lX%08lX"), m_lHighValue, m_lLowValue);
// Kill leading zero's
while (*pch == '0')
{
++pch;
}
// At least one digit...
if (*pch == '\0')
{
--pch;
}
str = pch;
return(str);
}
/***
*
* CIntlLargeNumber::ConvertStringToNumber
*
* Purpose:
*
* Given a CString convert it to LargeInteger.
*/
void CIntlLargeNumber::ConvertStringToNumber(const CString & str, BOOL * pfOk)
{
*pfOk = FALSE;
m_lHighValue = m_lLowValue = 0;
int j = str.GetLength();
if ( j > 16 || !j )
{
//
// Invalid string
//
return;
}
TCHAR sz[] = _T("0000000000000000");
TCHAR *pch;
::lstrcpy(sz + 16 - j, (LPCTSTR)str);
pch = sz + 8;
::swscanf(pch, _T("%08lX"), &m_lLowValue);
*pch = '\0';
::swscanf(sz, _T("%08lX"), &m_lHighValue);
*pfOk = TRUE;
return;
}
// Constructor taking a CString argument
CIntlLargeNumber::CIntlLargeNumber(const CString & str)
{
ConvertStringToNumber(str, &m_fInitOk);
}
// Assignment operator
CIntlLargeNumber & CIntlLargeNumber::operator =(const CString &str)
{
ConvertStringToNumber(str, &m_fInitOk);
return(*this);
}