Source code of Windows XP (NT5)
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.

372 lines
8.1 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows/NT **/
  3. /** Copyright(c) Microsoft Corporation, 1995 - 1997 **/
  4. /**********************************************************************/
  5. /*
  6. FILE HISTORY:
  7. */
  8. #define OEMRESOURCE
  9. #include "stdafx.h"
  10. #include <stdlib.h>
  11. #include <memory.h>
  12. #include <ctype.h>
  13. #include "objplus.h"
  14. #include "intlnum.h"
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char BASED_CODE THIS_FILE[] = __FILE__;
  18. #endif
  19. #define new DEBUG_NEW
  20. //
  21. // Initialise static thousand seperator string
  22. //
  23. CString CIntlNumber::m_strThousandSeperator(GetThousandSeperator());
  24. CString CIntlNumber::m_strBadNumber("--");
  25. /***
  26. *
  27. * CIntlNumber::GetThousandSeperator
  28. *
  29. * Purpose:
  30. *
  31. * Get the thousand seperator string from the registry (win32) or the
  32. * win.ini file (win16).
  33. *
  34. * Returns:
  35. *
  36. * A CString containing the system thousand seperator, or the
  37. * American default (",") in case of failure.
  38. *
  39. */
  40. CString CIntlNumber::GetThousandSeperator()
  41. {
  42. #define MAXLEN 6
  43. #ifdef _WIN32
  44. CString str;
  45. if (::GetLocaleInfo(GetUserDefaultLCID(), LOCALE_STHOUSAND, str.GetBuffer(MAXLEN), MAXLEN))
  46. {
  47. str.ReleaseBuffer();
  48. return(str);
  49. }
  50. Trace0("Couldn't get 1000 seperator from system, using american default");
  51. str = ",";
  52. return(str);
  53. #endif // _WIN32
  54. #ifdef _WIN16
  55. CString str;
  56. ::GetProfileString("Intl", "sThousand", ",", str.GetBuffer(MAXLEN), MAXLEN);
  57. str.ReleaseBuffer();
  58. return(str);
  59. #endif // _WIN16
  60. }
  61. /***
  62. *
  63. * CIntlNumber::Reset()
  64. *
  65. * Purpose:
  66. *
  67. * Reset the international settings. Usually in response to
  68. * a change in those international settings by the user.
  69. *
  70. * Notes:
  71. *
  72. * This is a publically available static function.
  73. *
  74. */
  75. void CIntlNumber::Reset()
  76. {
  77. CIntlNumber::m_strThousandSeperator = GetThousandSeperator();
  78. }
  79. /***
  80. *
  81. * CIntlNumber::ConvertNumberToString
  82. *
  83. * Purpose:
  84. *
  85. * Convert the given long number to a string, inserting thousand
  86. * seperators at the appropriate intervals.
  87. *
  88. * Arguments:
  89. *
  90. * const LONG l The number to convert
  91. *
  92. * Returns:
  93. *
  94. * A CString containing the number in string format.
  95. *
  96. */
  97. CString CIntlNumber::ConvertNumberToString(const LONG l)
  98. {
  99. // Default returned string:
  100. CString str = CIntlNumber::m_strBadNumber;
  101. LPTSTR lpOutString = str.GetBuffer(16);
  102. int outstrlen;
  103. // Forget about the negative sign for now.
  104. LONG lNum = (l >= 0) ? l : -l;
  105. outstrlen = 0;
  106. do
  107. {
  108. lpOutString[outstrlen++] = '0' + (TCHAR)(lNum % 10);
  109. lNum /= 10;
  110. // if more digits left and we're on a 1000 boundary (printed 3 digits,
  111. // or 3 digits + n*(3 digits + 1 comma), then print a 1000 separator.
  112. if (lNum != 0 && (outstrlen == 3 || outstrlen == 7 || outstrlen == 11))
  113. {
  114. lstrcpy (lpOutString + outstrlen, CIntlNumber::m_strThousandSeperator);
  115. outstrlen += m_strThousandSeperator.GetLength();
  116. }
  117. } while (lNum > 0);
  118. // Add a negative sign if necessary.
  119. if (l < 0L)
  120. {
  121. lpOutString[outstrlen++] = '-';
  122. }
  123. lpOutString[outstrlen] = '\0';
  124. str.ReleaseBuffer();
  125. str.MakeReverse();
  126. return(str);
  127. }
  128. /***
  129. *
  130. * CIntlNumber::ConvertStringToNumber
  131. *
  132. * Purpose:
  133. *
  134. * Given a CString, with optional thousand seperators, convert it to
  135. * a LONG.
  136. *
  137. * Arguments:
  138. *
  139. * const CString & str The string to convert
  140. * BOOL * pfOk Returns TRUE for successful conversion,
  141. * FALSE for failure.
  142. *
  143. * Returns:
  144. *
  145. * The return value is the number, or 0 if the string contained
  146. * invalid characters.
  147. *
  148. * Notes:
  149. *
  150. * If a negative sign is given, it must be the first character of
  151. * the string, immediately (no spaces) followed by the number.
  152. *
  153. * Optional thousand seperators can only be placed at the expected
  154. * 3 digit intervals. The function will return an error if a thousand
  155. * seperator is encountered elsewhere.
  156. *
  157. * [CAVEAT] This function will not accept thousand seperators of longer
  158. * than one character.
  159. *
  160. * No leading or trailing spaces will be acceptable.
  161. *
  162. */
  163. LONG CIntlNumber::ConvertStringToNumber(const CString & str, BOOL * pfOk)
  164. {
  165. CString strNumber(str);
  166. LONG lValue = 0L;
  167. LONG lBase = 1L;
  168. *pfOk = FALSE;
  169. BOOL fNegative = FALSE;
  170. // Empty strings are invalid
  171. if (strNumber.IsEmpty())
  172. {
  173. return(lValue);
  174. }
  175. int i;
  176. strNumber.MakeReverse();
  177. for (i=0; i<strNumber.GetLength(); ++i)
  178. {
  179. if ((strNumber[i] >= '0') && (strNumber[i] <= '9'))
  180. {
  181. lValue += (LONG)(strNumber[i] - '0') * lBase;
  182. lBase *= 10;
  183. }
  184. // It's not a digit, maybe a thousand seperator?
  185. // CAVEAT: If a thousand seperator of more than
  186. // one character is used, this won't work.
  187. else if ((strNumber[i] != m_strThousandSeperator[0]) ||
  188. (i != 3) && (i != 7) && (i != 11))
  189. {
  190. // Check for negative sign (at the end only)
  191. if ((strNumber[i] == '-') && (i == strNumber.GetLength()-1))
  192. {
  193. fNegative = TRUE;
  194. }
  195. else
  196. {
  197. // This is just invalid, since it is not a thousand
  198. // seperator in the proper location, nor a negative
  199. // sign.
  200. Trace1("Invalid character %c encountered in numeric conversion", (BYTE)strNumber[i]);
  201. return(0L);
  202. }
  203. }
  204. }
  205. if (fNegative)
  206. {
  207. lValue = -lValue;
  208. }
  209. *pfOk = TRUE;
  210. return (lValue);
  211. }
  212. // Constructor taking a CString argument
  213. CIntlNumber::CIntlNumber(const CString & str)
  214. {
  215. m_lValue = ConvertStringToNumber(str, &m_fInitOk);
  216. }
  217. // Assignment operator
  218. CIntlNumber & CIntlNumber::operator =(LONG l)
  219. {
  220. m_lValue = l;
  221. m_fInitOk = TRUE;
  222. return(*this);
  223. }
  224. // Assignment operator
  225. CIntlNumber & CIntlNumber::operator =(const CString &str)
  226. {
  227. m_lValue = ConvertStringToNumber(str, &m_fInitOk);
  228. return(*this);
  229. }
  230. // Conversion operator
  231. CIntlNumber::operator const CString() const
  232. {
  233. return(IsValid() ? ConvertNumberToString(m_lValue) : CIntlNumber::m_strBadNumber);
  234. }
  235. #ifdef _DEBUG
  236. //
  237. // Dump context to the debugging output
  238. //
  239. CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CIntlNumber& num)
  240. {
  241. dc << num.m_lValue;
  242. return(dc);
  243. }
  244. #endif // _DEBUG
  245. // Initialise static thousand seperator string
  246. CString CIntlLargeNumber::m_strBadNumber("--");
  247. /***
  248. *
  249. * CIntlLargeNumber::ConvertNumberToString
  250. *
  251. * Purpose:
  252. *
  253. * Convert the given long number to a string.
  254. *
  255. * Returns:
  256. *
  257. * A CString containing the number in string format.
  258. *
  259. */
  260. CString CIntlLargeNumber::ConvertNumberToString()
  261. {
  262. CString str;
  263. TCHAR sz[20];
  264. TCHAR *pch = sz;
  265. ::wsprintf(sz, _T("%08lX%08lX"), m_lHighValue, m_lLowValue);
  266. // Kill leading zero's
  267. while (*pch == '0')
  268. {
  269. ++pch;
  270. }
  271. // At least one digit...
  272. if (*pch == '\0')
  273. {
  274. --pch;
  275. }
  276. str = pch;
  277. return(str);
  278. }
  279. /***
  280. *
  281. * CIntlLargeNumber::ConvertStringToNumber
  282. *
  283. * Purpose:
  284. *
  285. * Given a CString convert it to LargeInteger.
  286. */
  287. void CIntlLargeNumber::ConvertStringToNumber(const CString & str, BOOL * pfOk)
  288. {
  289. *pfOk = FALSE;
  290. m_lHighValue = m_lLowValue = 0;
  291. int j = str.GetLength();
  292. if ( j > 16 || !j )
  293. {
  294. //
  295. // Invalid string
  296. //
  297. return;
  298. }
  299. TCHAR sz[] = _T("0000000000000000");
  300. TCHAR *pch;
  301. ::lstrcpy(sz + 16 - j, (LPCTSTR)str);
  302. pch = sz + 8;
  303. ::swscanf(pch, _T("%08lX"), &m_lLowValue);
  304. *pch = '\0';
  305. ::swscanf(sz, _T("%08lX"), &m_lHighValue);
  306. *pfOk = TRUE;
  307. return;
  308. }
  309. // Constructor taking a CString argument
  310. CIntlLargeNumber::CIntlLargeNumber(const CString & str)
  311. {
  312. ConvertStringToNumber(str, &m_fInitOk);
  313. }
  314. // Assignment operator
  315. CIntlLargeNumber & CIntlLargeNumber::operator =(const CString &str)
  316. {
  317. ConvertStringToNumber(str, &m_fInitOk);
  318. return(*this);
  319. }