|
|
/**********************************************************************/ /** 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); }
|