/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1995 - 1997 **/ /**********************************************************************/ /* FILE HISTORY: */ #define OEMRESOURCE #include "stdafx.h" #include #include #include #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= '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); }