373 lines
8.1 KiB
C++
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);
|
||
|
}
|