Leaked source code of windows server 2003
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.

940 lines
31 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1997, Microsoft Corporation.
  4. //
  5. // File: OutFmt.cxx
  6. //
  7. // Contents: COutputFormat
  8. //
  9. // History: 11-Jun-97 KyleP Moved from WQIter.cxx
  10. //
  11. //----------------------------------------------------------------------------
  12. #include <pch.cxx>
  13. #pragma hdrstop
  14. static WCHAR * wcsDefaultBoolVectorPrefix = L" ";
  15. static WCHAR * wcsDefaultBoolVectorSeparator = L" ";
  16. static WCHAR * wcsDefaultBoolVectorSuffix = L" ";
  17. static WCHAR * wcsDefaultCurrencyVectorPrefix = L" ";
  18. static WCHAR * wcsDefaultCurrencyVectorSeparator = L" ";
  19. static WCHAR * wcsDefaultCurrencyVectorSuffix = L" ";
  20. static WCHAR * wcsDefaultDateVectorPrefix = L" ";
  21. static WCHAR * wcsDefaultDateVectorSeparator = L" ";
  22. static WCHAR * wcsDefaultDateVectorSuffix = L" ";
  23. static WCHAR * wcsDefaultNumberVectorPrefix = L" ";
  24. static WCHAR * wcsDefaultNumberVectorSeparator = L" ";
  25. static WCHAR * wcsDefaultNumberVectorSuffix = L" ";
  26. static WCHAR * wcsDefaultStringVectorPrefix = L" ";
  27. static WCHAR * wcsDefaultStringVectorSeparator = L" ";
  28. static WCHAR * wcsDefaultStringVectorSuffix = L" ";
  29. //+---------------------------------------------------------------------------
  30. //
  31. // Function: COutputFormat::COutputFormat - public
  32. //
  33. // Arguments: [webServer] - makes a copy of the web server to resolve CGI
  34. // variables
  35. //
  36. // Synopsis: Constructor
  37. //
  38. // History: 96-Jan-18 DwightKr Created
  39. // 96-Feb-26 DwightKr Added vector formatting
  40. //
  41. //----------------------------------------------------------------------------
  42. COutputFormat::COutputFormat( CWebServer & webServer )
  43. : CWebServer( webServer ),
  44. _wcsBoolVectorPrefix( wcsDefaultBoolVectorPrefix ),
  45. _wcsBoolVectorSeparator( wcsDefaultBoolVectorSeparator ),
  46. _wcsBoolVectorSuffix( wcsDefaultBoolVectorSuffix ),
  47. _wcsCurrencyVectorPrefix( wcsDefaultCurrencyVectorPrefix ),
  48. _wcsCurrencyVectorSeparator( wcsDefaultCurrencyVectorSeparator ),
  49. _wcsCurrencyVectorSuffix( wcsDefaultCurrencyVectorSuffix ),
  50. _wcsDateVectorPrefix( wcsDefaultDateVectorPrefix ),
  51. _wcsDateVectorSeparator( wcsDefaultDateVectorSeparator ),
  52. _wcsDateVectorSuffix( wcsDefaultDateVectorSuffix ),
  53. _wcsNumberVectorPrefix( wcsDefaultNumberVectorPrefix ),
  54. _wcsNumberVectorSeparator( wcsDefaultNumberVectorSeparator ),
  55. _wcsNumberVectorSuffix( wcsDefaultNumberVectorSuffix ),
  56. _wcsStringVectorPrefix( wcsDefaultStringVectorPrefix ),
  57. _wcsStringVectorSeparator( wcsDefaultStringVectorSeparator ),
  58. _wcsStringVectorSuffix( wcsDefaultStringVectorSuffix )
  59. {
  60. _numberFormat.lpDecimalSep = 0;
  61. _numberFormat.lpThousandSep = 0;
  62. _currencyFormat.lpDecimalSep = 0;
  63. _currencyFormat.lpThousandSep = 0;
  64. _currencyFormat.lpCurrencySymbol = 0;
  65. }
  66. //+---------------------------------------------------------------------------
  67. //
  68. // Function: COutputFormat::GetIntegerFormat - private
  69. //
  70. // Synopsis: Formats a number and returns results in the string
  71. // buffer supplied.
  72. //
  73. // Arguments: [wcsInput] - string to convert
  74. // [wcsNumber] - output location for results
  75. // [_cwcNumber] - length of output buffer in WCHARs
  76. //
  77. // Returns: The number of characters in the final string, less the NULL
  78. // terminator.
  79. //
  80. // History: 96-Jan-18 DwightKr Created
  81. //
  82. //----------------------------------------------------------------------------
  83. int COutputFormat::GetIntegerFormat( WCHAR * const wcsInput,
  84. WCHAR * wcsNumber,
  85. ULONG cwcNumber )
  86. {
  87. Win4Assert( 0 != _numberFormat.lpDecimalSep );
  88. Win4Assert( 0 != _numberFormat.lpThousandSep );
  89. Win4Assert( InvalidLCID != GetLCID() );
  90. ULONG numDigits = _numberFormat.NumDigits;
  91. _numberFormat.NumDigits = 0;
  92. int cwcResult = ::GetNumberFormat( GetLCID(),
  93. 0,
  94. wcsInput,
  95. &_numberFormat,
  96. wcsNumber,
  97. cwcNumber );
  98. _numberFormat.NumDigits = numDigits;
  99. if ( 0 == cwcResult )
  100. {
  101. THROW( CException() );
  102. }
  103. return cwcResult - 1;
  104. }
  105. //+---------------------------------------------------------------------------
  106. //
  107. // Function: COutputFormat::FormatNumber - public
  108. //
  109. // Synopsis: Formats a unsigned number and returns results in the string
  110. // buffer supplied.
  111. //
  112. // Arguments: [ulNumber] - number to convert
  113. // [wcsNumber] - output location for results
  114. // [cwcNumber] - length of output buffer in WCHARs
  115. //
  116. // Returns: The number of characters in the final string, less the NULL
  117. // terminator.
  118. //
  119. // History: 96-Jan-18 DwightKr Created
  120. //
  121. //----------------------------------------------------------------------------
  122. int COutputFormat::FormatNumber( ULONG ulNumber,
  123. WCHAR * wcsNumber,
  124. ULONG cwcNumber )
  125. {
  126. WCHAR wcsBuffer[40];
  127. IDQ_ultow( ulNumber, wcsBuffer );
  128. return GetIntegerFormat( wcsBuffer, wcsNumber, cwcNumber );
  129. }
  130. //+---------------------------------------------------------------------------
  131. //
  132. // Function: COutputFormat::FormatNumber
  133. //
  134. // Synopsis: Formats a signed number and returns results in the string
  135. // buffer supplied.
  136. //
  137. // Arguments: [lNumber] - number to convert
  138. // [wcsNumber] - output location for results
  139. // [cwcNumber] - length of output buffer in WCHARs
  140. //
  141. // Returns: The number of characters in the final string, less the NULL
  142. // terminator.
  143. //
  144. // History: 96-Jan-18 DwightKr Created
  145. //
  146. //----------------------------------------------------------------------------
  147. int COutputFormat::FormatNumber( LONG lNumber,
  148. WCHAR * wcsNumber,
  149. ULONG cwcNumber )
  150. {
  151. WCHAR wcsBuffer[40];
  152. IDQ_ltow( lNumber, wcsBuffer );
  153. return GetIntegerFormat( wcsBuffer, wcsNumber, cwcNumber );
  154. }
  155. //+---------------------------------------------------------------------------
  156. //
  157. // Function: COutputFormat::FormatNumber
  158. //
  159. // Synopsis: Formats a _int64 and returns results in the string
  160. // buffer supplied.
  161. //
  162. // Arguments: [i64Number] - number to convert
  163. // [wcsNumber] - output location for results
  164. // [cwcNumber] - length of output buffer in WCHARs
  165. //
  166. // Returns: The number of characters in the final string, less the NULL
  167. // terminator.
  168. //
  169. // History: 96-Jan-18 DwightKr Created
  170. //
  171. //----------------------------------------------------------------------------
  172. int COutputFormat::FormatNumber( _int64 i64Number,
  173. WCHAR * wcsNumber,
  174. ULONG cwcNumber )
  175. {
  176. WCHAR wcsBuffer[40];
  177. IDQ_lltow( i64Number, wcsBuffer );
  178. return GetIntegerFormat( wcsBuffer, wcsNumber, cwcNumber );
  179. }
  180. //+---------------------------------------------------------------------------
  181. //
  182. // Function: COutputFormat::FormatNumber
  183. //
  184. // Synopsis: Formats a unsigned _int64 and returns results in the string
  185. // buffer supplied.
  186. //
  187. // Arguments: [ui64Number] - number to convert
  188. // [wcsNumber] - output location for results
  189. // [cwcNumber] - length of output buffer in WCHARs
  190. //
  191. // Returns: The number of characters in the final string, less the NULL
  192. // terminator.
  193. //
  194. // History: 96-Jan-18 DwightKr Created
  195. //
  196. //----------------------------------------------------------------------------
  197. int COutputFormat::FormatNumber( unsigned _int64 ui64Number,
  198. WCHAR * wcsNumber,
  199. ULONG cwcNumber )
  200. {
  201. WCHAR wcsBuffer[40];
  202. IDQ_ulltow( ui64Number, wcsBuffer );
  203. return GetIntegerFormat( wcsBuffer, wcsNumber, cwcNumber );
  204. }
  205. //+---------------------------------------------------------------------------
  206. //
  207. // Method: COutputFormat::FormatFloatRaw, public
  208. //
  209. // Synopsis: Formats a floating point number and returns results in the
  210. // string buffer supplied.
  211. //
  212. // Arguments: [flt] - number to be formatted
  213. // [cchPrec] - number of digits of precision to use
  214. // [pwszNumber] - output location for results
  215. // [cchNumber] - length of output buffer in WCHARs
  216. //
  217. // Returns: The number of characters in the final string, less the NULL
  218. // terminator.
  219. //
  220. // Notes: GetNumberFormat isn't really very useful for numbers with
  221. // very large or small magnitudes. It gives up when there are
  222. // about 100 digits to the left of the decimal place.
  223. //
  224. // History: 96-Jan-18 DwightKr Created
  225. // 96-May-22 DwightKr Increased buffer size
  226. // 97-Mar-12 AlanW Changed signature to better handle
  227. // single-precision floating point
  228. //
  229. //----------------------------------------------------------------------------
  230. int COutputFormat::FormatFloatRaw( double flt,
  231. unsigned cchPrec,
  232. WCHAR * pwszNumber,
  233. ULONG cchNumber )
  234. {
  235. int iDec, fSign;
  236. char * pszCvt = _ecvt( flt, cchPrec, &iDec, &fSign );
  237. WCHAR *pwsz = pwszNumber;
  238. if (fSign)
  239. *pwsz++ = L'-';
  240. if (iDec <= 0)
  241. {
  242. *pwsz++ = L'.';
  243. while (iDec < 0)
  244. {
  245. *pwsz++ = L'0';
  246. iDec++;
  247. }
  248. }
  249. for (unsigned i=0; i< cchPrec; i++)
  250. {
  251. *pwsz++ = *pszCvt++;
  252. if (iDec && --iDec == 0)
  253. *pwsz++ = L'.';
  254. }
  255. while (iDec > 0)
  256. {
  257. *pwsz++ = L'0';
  258. iDec--;
  259. }
  260. *pwsz = L'\0';
  261. int cchResult = (int)(pwsz - pwszNumber);
  262. Win4Assert ((unsigned)cchResult < cchNumber);
  263. if ((unsigned)cchResult >= cchNumber)
  264. {
  265. ciGibDebugOut((DEB_WARN, "FormatFloatRaw - string buffer overflow!\n"));
  266. cchResult = -1;
  267. }
  268. return cchResult;
  269. } //FormatFloatRaw
  270. //+---------------------------------------------------------------------------
  271. //
  272. // Method: COutputFormat::FormatFloat, public
  273. //
  274. // Synopsis: Formats a floating point number and returns results in the
  275. // string buffer supplied.
  276. //
  277. // Arguments: [flt] - number to be formatted
  278. // [cchPrec] - number of digits of precision to use
  279. // [pwszNumber] - output location for results
  280. // [cchNumber] - length of output buffer in WCHARs
  281. //
  282. // Returns: The number of characters in the final string, less the NULL
  283. // terminator.
  284. //
  285. // Notes: GetNumberFormat isn't really very useful for numbers with
  286. // very large or small magnitudes. It gives up when there are
  287. // about 100 digits to the left of the decimal place.
  288. //
  289. // History: 96-Jan-18 DwightKr Created
  290. // 96-May-22 DwightKr Increased buffer size
  291. // 97-Mar-12 AlanW Changed signature to better handle
  292. // single-precision floating point
  293. //
  294. //----------------------------------------------------------------------------
  295. int COutputFormat::FormatFloat( double flt,
  296. unsigned cchPrec,
  297. WCHAR * pwszNumber,
  298. ULONG cchNumber )
  299. {
  300. Win4Assert( 0 != _numberFormat.lpDecimalSep );
  301. Win4Assert( 0 != _numberFormat.lpThousandSep );
  302. Win4Assert( InvalidLCID != GetLCID() );
  303. WCHAR pwszInput[ maxFloatSize ];
  304. WCHAR *pwsz = pwszInput;
  305. int cch = FormatFloatRaw( flt,
  306. cchPrec,
  307. pwszInput,
  308. sizeof pwszInput / sizeof pwszInput[0]);
  309. Win4Assert( cch > 0 );
  310. int cchResult = ::GetNumberFormat( GetLCID(),
  311. 0,
  312. pwszInput,
  313. &_numberFormat,
  314. pwszNumber,
  315. cchNumber );
  316. if ( 0 == cchResult )
  317. {
  318. ciGibDebugOut(( DEB_WARN, "FormatFloat - GetNumberFormat failed, error = %d\n", GetLastError() ));
  319. THROW( CException() );
  320. }
  321. return cchResult - 1;
  322. } //FormatFloat
  323. //+---------------------------------------------------------------------------
  324. //
  325. // Function: COutputFormat::FormatDate
  326. //
  327. // Synopsis: Formats a SYSTEMTIME and returns results in the string
  328. // buffer supplied.
  329. //
  330. // Arguments: [sysTime] - date to convert
  331. // [wcsDate] - output location for results
  332. // [cwcDate] - length of output buffer in WCHARs
  333. //
  334. // Returns: The number of characters in the final string, less the NULL
  335. // terminator.
  336. //
  337. // History: 96-Jan-18 DwightKr Created
  338. //
  339. //----------------------------------------------------------------------------
  340. int COutputFormat::FormatDate(
  341. SYSTEMTIME & sysTime,
  342. WCHAR * wcsDate,
  343. ULONG cwcDate )
  344. {
  345. *wcsDate = 0;
  346. Win4Assert( InvalidLCID != GetLCID() );
  347. ULONG ulMethod = TheIDQRegParams.GetDateTimeFormatting();
  348. // Fixed, non-localized formatting
  349. if ( IS_DATETIME_FORMATTING_FAST_LCID == ulMethod )
  350. {
  351. if ( cwcDate < 10 )
  352. return 0;
  353. wsprintf( wcsDate, L"%4d/%02d/%02d",
  354. (DWORD) sysTime.wYear,
  355. (DWORD) sysTime.wMonth,
  356. (DWORD) sysTime.wDay );
  357. return 10;
  358. }
  359. // Format the date using the locale provided.
  360. ULONG ulFlags = DATE_SHORTDATE;
  361. if ( IS_DATETIME_FORMATTING_SYSTEM_LCID == ulMethod )
  362. ulFlags |= LOCALE_NOUSEROVERRIDE;
  363. ULONG cwcUsed = GetDateFormat( GetLCID(),
  364. ulFlags,
  365. &sysTime,
  366. 0,
  367. wcsDate,
  368. cwcDate );
  369. if ( 0 != cwcUsed )
  370. {
  371. Win4Assert( 0 == wcsDate[cwcUsed - 1] );
  372. // cwcUsed includes the null termination -- remove it.
  373. return cwcUsed - 1;
  374. }
  375. #if DBG == 1
  376. ULONG error = GetLastError();
  377. ciGibDebugOut(( DEB_ERROR,
  378. "GetDateFormat failed: 0x%x\n",
  379. error ));
  380. // ERROR_INVALID_PARAMETER indicates that the date is
  381. // bogus -- perhaps because the file was deleted.
  382. if ( ERROR_INVALID_PARAMETER != error )
  383. Win4Assert( !"GetTimeFormat failed" );
  384. #endif // DBG == 1
  385. return 0;
  386. } //FormatDate
  387. //+---------------------------------------------------------------------------
  388. //
  389. // Function: COutputFormat::FormatTime
  390. //
  391. // Synopsis: Formats a SYSTEMTIME and returns results in the string
  392. // buffer supplied.
  393. //
  394. // Arguments: [sysTime] - date to convert
  395. // [wcsTime] - output location for results
  396. // [cwcTime] - length of output buffer in WCHARs
  397. //
  398. // Returns: The number of characters in the final string, less the NULL
  399. // terminator.
  400. //
  401. // History: 96-Jan-18 DwightKr Created
  402. //
  403. //----------------------------------------------------------------------------
  404. int COutputFormat::FormatTime(
  405. SYSTEMTIME & sysTime,
  406. WCHAR * wcsTime,
  407. ULONG cwcTime )
  408. {
  409. *wcsTime = 0;
  410. Win4Assert( InvalidLCID != GetLCID() );
  411. ULONG ulMethod = TheIDQRegParams.GetDateTimeFormatting();
  412. // Fixed, non-localized formatting
  413. if ( IS_DATETIME_FORMATTING_FAST_LCID == ulMethod )
  414. {
  415. if ( cwcTime < 8 )
  416. return 0;
  417. wsprintf( wcsTime, L"%2d:%02d:%02d",
  418. (DWORD) sysTime.wHour,
  419. (DWORD) sysTime.wMinute,
  420. (DWORD) sysTime.wSecond );
  421. return 8;
  422. }
  423. // Format the time using the locale provided.
  424. ULONG ulFlags = ( IS_DATETIME_FORMATTING_USER_LCID == ulMethod ) ?
  425. 0 : LOCALE_NOUSEROVERRIDE;
  426. ULONG cwcUsed = GetTimeFormat( GetLCID(),
  427. ulFlags,
  428. &sysTime,
  429. 0,
  430. wcsTime,
  431. cwcTime );
  432. if ( 0 != cwcUsed )
  433. {
  434. Win4Assert( 0 == wcsTime[cwcUsed - 1] );
  435. // cwcUsed includes the null termination -- remove it.
  436. return cwcUsed - 1;
  437. }
  438. #if DBG == 1
  439. ULONG error = GetLastError();
  440. ciGibDebugOut(( DEB_ERROR,
  441. "GetTimeFormat failed: 0x%x\n",
  442. error ));
  443. // ERROR_INVALID_PARAMETER indicates that the date is
  444. // bogus -- perhaps because the file was deleted.
  445. if ( ERROR_INVALID_PARAMETER != error )
  446. Win4Assert( !"GetTimeFormat failed" );
  447. #endif // DBG == 1
  448. return 0;
  449. } //FormatTime
  450. //+---------------------------------------------------------------------------
  451. //
  452. // Function: COutputFormat::FormatDateTime
  453. //
  454. // Synopsis: Formats a SYSTEMTIME and returns results in the string
  455. // buffer supplied.
  456. //
  457. // Arguments: [sysTime] - date to convert
  458. // [wcsDate] - output location for results
  459. // [cwcDate] - length of output buffer in WCHARs
  460. //
  461. // Returns: The number of characters in the final string, less the NULL
  462. // terminator.
  463. //
  464. // History: 96-Jan-18 DwightKr Created
  465. //
  466. //----------------------------------------------------------------------------
  467. int COutputFormat::FormatDateTime( SYSTEMTIME & SysTime,
  468. WCHAR * wcsDate,
  469. ULONG cwcDate )
  470. {
  471. //
  472. // Convert UTC/GMT to local system time if set in the registry
  473. //
  474. if ( TheIDQRegParams.GetDateTimeLocal() )
  475. {
  476. FILETIME ft, ftLocal;
  477. SystemTimeToFileTime( &SysTime, &ft );
  478. FileTimeToLocalFileTime( &ft, &ftLocal );
  479. FileTimeToSystemTime( &ftLocal, &SysTime );
  480. }
  481. int cwcDateBuffer = FormatDate( SysTime, wcsDate, cwcDate );
  482. wcsDate[cwcDateBuffer] = L' ';
  483. int cwcBuffer = max( 0, ( (int) (cwcDate - cwcDateBuffer ) ) - 2 );
  484. int cwcTimeBuffer = FormatTime( SysTime,
  485. wcsDate+cwcDateBuffer+1,
  486. cwcBuffer );
  487. return cwcTimeBuffer + cwcDateBuffer + 1;
  488. } //FormatDateTime
  489. //+---------------------------------------------------------------------------
  490. //
  491. // Function: COutputFormat::FormatCurrency
  492. //
  493. // Synopsis: Formats a CY and returns results in the string
  494. // buffer supplied.
  495. //
  496. // Arguments: [cyValue] - number to convert
  497. // [wcsCurrency] - output location for results
  498. // [cwcCurrency] - length of output buffer in WCHARs
  499. //
  500. // Returns: The number of characters in the final string, less the NULL
  501. // terminator.
  502. //
  503. // History: 96-Jan-18 DwightKr Created
  504. //
  505. //----------------------------------------------------------------------------
  506. int COutputFormat::FormatCurrency( CY cyValue,
  507. WCHAR * wcsCurrency,
  508. ULONG cwcCurrency )
  509. {
  510. Win4Assert( 0 != _numberFormat.lpDecimalSep );
  511. Win4Assert( 0 != _numberFormat.lpThousandSep );
  512. Win4Assert( 0 != _currencyFormat.lpDecimalSep );
  513. Win4Assert( 0 != _currencyFormat.lpThousandSep );
  514. Win4Assert( InvalidLCID != GetLCID() );
  515. WCHAR wcsBuffer[ maxFloatSize ];
  516. double dblValue;
  517. VarR8FromCy( cyValue, &dblValue );
  518. swprintf( wcsBuffer, L"%lf", dblValue );
  519. int cwcResult = ::GetCurrencyFormat( GetLCID(),
  520. 0,
  521. wcsBuffer,
  522. &_currencyFormat,
  523. wcsCurrency,
  524. cwcCurrency );
  525. if ( 0 == cwcResult )
  526. {
  527. THROW( CException() );
  528. }
  529. return cwcResult - 1;
  530. } //FormatCurrency
  531. //+---------------------------------------------------------------------------
  532. //
  533. // Function: COutputFormat::LoadNumberFormatInfo - public
  534. //
  535. // Synopsis: Fills the numberFormat stucture with formatting information
  536. // used to subsequently format numbers.
  537. //
  538. // History: 97-Jun-24 t-elainc Created
  539. //
  540. //----------------------------------------------------------------------------
  541. void COutputFormat::LoadNumberFormatInfo( LCID lcid )
  542. {
  543. LoadNumberFormatInfo(lcid, LocaleToCodepage(lcid) );
  544. }
  545. //+---------------------------------------------------------------------------
  546. //
  547. // Function: ConvertGroupingStringToInt
  548. //
  549. // Synopsis: Converts a grouping string from the registry to an integer,
  550. // as required by the Win32 number formatting API
  551. //
  552. // History: 5-Feb-99 dlee Stole from the Win32 implementation
  553. //
  554. //----------------------------------------------------------------------------
  555. int ConvertGroupingStringToInt( WCHAR const * pwcGrouping )
  556. {
  557. XGrowable<WCHAR> xDest( 1 + wcslen( pwcGrouping ) );
  558. WCHAR * pDest = xDest.Get();
  559. //
  560. // Filter out all non-numeric values and all zero values.
  561. // Store the result in the destination buffer.
  562. //
  563. WCHAR const * pSrc = pwcGrouping;
  564. while (0 != *pSrc)
  565. {
  566. if ( ( *pSrc < L'1' ) || ( *pSrc > L'9' ) )
  567. {
  568. pSrc++;
  569. }
  570. else
  571. {
  572. if (pSrc != pDest)
  573. *pDest = *pSrc;
  574. pSrc++;
  575. pDest++;
  576. }
  577. }
  578. //
  579. // Make sure there is something in the destination buffer.
  580. // Also, see if we need to add a zero in the case of 3;2 becomes 320.
  581. //
  582. if ( ( pDest == xDest.Get() ) || ( *(pSrc - 1) != L'0' ) )
  583. {
  584. *pDest = L'0';
  585. pDest++;
  586. }
  587. // Null terminate the buffer.
  588. *pDest = 0;
  589. // Convert the string to an integer.
  590. return _wtoi( xDest.Get() );
  591. } //ConvertGroupingStringToInt
  592. //+---------------------------------------------------------------------------
  593. //
  594. // Function: COutputFormat::LoadNumberFormatInfo - public
  595. //
  596. // Synopsis: Fills the numberFormat stucture with formatting information
  597. // used to subsequently format numbers.
  598. //
  599. // History: 96-Jan-18 DwightKr Created
  600. //
  601. //----------------------------------------------------------------------------
  602. void COutputFormat::LoadNumberFormatInfo( LCID lcid , ULONG codepage)
  603. {
  604. Win4Assert( InvalidLCID != lcid );
  605. //
  606. // If we're already loaded, then don't do it again.
  607. //
  608. if ( lcid == GetLCID() && 0 != _numberFormat.lpDecimalSep )
  609. return;
  610. delete _numberFormat.lpDecimalSep;
  611. delete _numberFormat.lpThousandSep;
  612. delete _currencyFormat.lpDecimalSep;
  613. delete _currencyFormat.lpThousandSep;
  614. _numberFormat.lpDecimalSep = 0;
  615. _numberFormat.lpThousandSep = 0;
  616. _currencyFormat.lpDecimalSep = 0;
  617. _currencyFormat.lpThousandSep = 0;
  618. Win4Assert( 0 == _numberFormat.lpDecimalSep );
  619. Win4Assert( 0 == _numberFormat.lpThousandSep );
  620. Win4Assert( 0 == _currencyFormat.lpDecimalSep );
  621. Win4Assert( 0 == _currencyFormat.lpThousandSep );
  622. SetLCID( lcid, 0, 0 );
  623. TheFormattingCache.GetFormattingInfo( lcid,
  624. _numberFormat,
  625. _currencyFormat );
  626. SetCodePage( codepage );
  627. ciGibDebugOut(( DEB_ITRACE, "Using a codePage of 0x%x for locale 0x%x\n",
  628. CodePage(),
  629. GetLCID() ));
  630. } //LoadNumberFormatInfo
  631. //+---------------------------------------------------------------------------
  632. //
  633. // Method: CFormatItem::CFormatItem, public
  634. //
  635. // Synopsis: Constructs formatting info.
  636. //
  637. // Arguments: [lcid] -- The locale to use.
  638. //
  639. // History: 99-Feb-10 dlee Created
  640. //
  641. //----------------------------------------------------------------------------
  642. CFormatItem::CFormatItem( LCID lcid ) : _lcid( lcid )
  643. {
  644. WCHAR wcsBuffer[256];
  645. RtlZeroMemory( &_numberFormat, sizeof _numberFormat );
  646. RtlZeroMemory( &_currencyFormat, sizeof _currencyFormat );
  647. // Get the number of decimal digits.
  648. GetLocaleInfo(lcid, LOCALE_IDIGITS, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  649. _numberFormat.NumDigits = _wtoi(wcsBuffer);
  650. // Get the leading zero in decimal fields option.
  651. GetLocaleInfo(lcid, LOCALE_ILZERO, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  652. _numberFormat.LeadingZero = _wtoi(wcsBuffer);
  653. // Get the negative ordering.
  654. GetLocaleInfo(lcid, LOCALE_INEGNUMBER, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  655. _numberFormat.NegativeOrder = _wtoi(wcsBuffer);
  656. // Get the grouping left of the decimal.
  657. GetLocaleInfo(lcid, LOCALE_SGROUPING, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  658. _numberFormat.Grouping = ConvertGroupingStringToInt( wcsBuffer );
  659. ciGibDebugOut(( DEB_ITRACE, "grouping '%ws' -> %d\n",
  660. wcsBuffer, _numberFormat.Grouping ));
  661. // Get the decimal separator.
  662. GetLocaleInfo(lcid, LOCALE_SDECIMAL, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  663. XPtrST<WCHAR> xNumDecimalSep( CopyString( wcsBuffer ) );
  664. _numberFormat.lpDecimalSep = xNumDecimalSep.GetPointer();
  665. // Get the thousand separator.
  666. GetLocaleInfo(lcid, LOCALE_STHOUSAND, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  667. XPtrST<WCHAR> xNumThousandSep( CopyString( wcsBuffer ) );
  668. _numberFormat.lpThousandSep = xNumThousandSep.GetPointer();
  669. // Get the number of currency digits.
  670. GetLocaleInfo(lcid, LOCALE_ICURRDIGITS, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  671. _currencyFormat.NumDigits = _wtoi(wcsBuffer);
  672. GetLocaleInfo(lcid, LOCALE_ILZERO, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  673. // Get the leading zero in currency fields option.
  674. _currencyFormat.LeadingZero = _wtoi(wcsBuffer);
  675. // Get the currency grouping left of the decimal.
  676. GetLocaleInfo(lcid, LOCALE_SMONGROUPING, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  677. _currencyFormat.Grouping = _wtoi(wcsBuffer);
  678. // Get the currency decimal separator.
  679. GetLocaleInfo(lcid, LOCALE_SMONDECIMALSEP, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  680. XPtrST<WCHAR> xCurDecimalSep( CopyString( wcsBuffer ) );
  681. _currencyFormat.lpDecimalSep = xCurDecimalSep.GetPointer();
  682. // Get the currency thousand separator.
  683. GetLocaleInfo(lcid, LOCALE_SMONTHOUSANDSEP, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  684. XPtrST<WCHAR> xCurThousandSep( CopyString( wcsBuffer ) );
  685. _currencyFormat.lpThousandSep = xCurThousandSep.GetPointer();
  686. // Get the negative ordering.
  687. GetLocaleInfo(lcid, LOCALE_INEGCURR, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  688. _currencyFormat.NegativeOrder = _wtoi(wcsBuffer);
  689. // Get the positive ordering.
  690. GetLocaleInfo(lcid, LOCALE_ICURRENCY, wcsBuffer, sizeof(wcsBuffer) / sizeof(WCHAR));
  691. _currencyFormat.PositiveOrder = _wtoi(wcsBuffer);
  692. _currencyFormat.lpCurrencySymbol = L"";
  693. xNumDecimalSep.Acquire();
  694. xNumThousandSep.Acquire();
  695. xCurDecimalSep.Acquire();
  696. xCurThousandSep.Acquire();
  697. } //CFormatItem
  698. //+---------------------------------------------------------------------------
  699. //
  700. // Method: CFormatItem::~CFormatItem, public
  701. //
  702. // Synopsis: Frees formatting info.
  703. //
  704. // History: 99-Feb-10 dlee Created
  705. //
  706. //----------------------------------------------------------------------------
  707. CFormatItem::~CFormatItem()
  708. {
  709. delete _numberFormat.lpDecimalSep;
  710. delete _numberFormat.lpThousandSep;
  711. delete _currencyFormat.lpDecimalSep;
  712. delete _currencyFormat.lpThousandSep;
  713. } //~CFormatItem
  714. //+---------------------------------------------------------------------------
  715. //
  716. // Method: CFormatItem::Copy, public
  717. //
  718. // Synopsis: Copies formatting info into the arguments
  719. //
  720. // Arguments: [numberFormat] -- Where the number format is copied to
  721. // [currencyFormat] -- Where the currency format is copied to
  722. //
  723. // History: 99-Feb-10 dlee Created
  724. //
  725. //----------------------------------------------------------------------------
  726. void CFormatItem::Copy(
  727. NUMBERFMT & numberFormat,
  728. CURRENCYFMT & currencyFormat ) const
  729. {
  730. XPtrST<WCHAR> xNumDecimalSep( CopyString( _numberFormat.lpDecimalSep ) );
  731. XPtrST<WCHAR> xNumThousandSep( CopyString( _numberFormat.lpThousandSep ) );
  732. XPtrST<WCHAR> xCurDecimalSep( CopyString( _currencyFormat.lpDecimalSep ) );
  733. XPtrST<WCHAR> xCurThousandSep( CopyString( _currencyFormat.lpDecimalSep ) );
  734. RtlCopyMemory( &numberFormat, &_numberFormat, sizeof NUMBERFMT );
  735. RtlCopyMemory( &currencyFormat, &_currencyFormat, sizeof CURRENCYFMT );
  736. numberFormat.lpDecimalSep = xNumDecimalSep.Acquire();
  737. numberFormat.lpThousandSep = xNumThousandSep.Acquire();
  738. currencyFormat.lpDecimalSep = xCurDecimalSep.Acquire();
  739. currencyFormat.lpThousandSep = xCurThousandSep.Acquire();
  740. } //Copy
  741. //+---------------------------------------------------------------------------
  742. //
  743. // Method: CFormattingCache::GetFormattingInfo, public
  744. //
  745. // Synopsis: Copies formatting info for lcid into the arguments
  746. //
  747. // Arguments: [lcid] -- Locale of info to lookup
  748. // [numberFormat] -- Where the number format is copied to
  749. // [currencyFormat] -- Where the currency format is copied to
  750. //
  751. // History: 99-Feb-10 dlee Created
  752. //
  753. //----------------------------------------------------------------------------
  754. void CFormattingCache::GetFormattingInfo(
  755. LCID lcid,
  756. NUMBERFMT & numberFormat,
  757. CURRENCYFMT & currencyFormat )
  758. {
  759. CLock lock( _mutex );
  760. for ( unsigned i = 0; i < _aItems.Count(); i++ )
  761. {
  762. if ( _aItems[i]->GetLCID() == lcid )
  763. {
  764. _aItems[i]->Copy( numberFormat, currencyFormat );
  765. return;
  766. }
  767. }
  768. XPtr<CFormatItem> xItem( new CFormatItem( lcid ) );
  769. xItem->Copy( numberFormat, currencyFormat );
  770. _aItems.Add( xItem.GetPointer(), _aItems.Count() );
  771. xItem.Acquire();
  772. } //GetFormattingInfo
  773. //+---------------------------------------------------------------------------
  774. //
  775. // Method: CFormattingCache::Purge, public
  776. //
  777. // Synopsis: Purges the cache of all entries
  778. //
  779. // History: 99-Feb-10 dlee Created
  780. //
  781. //----------------------------------------------------------------------------
  782. void CFormattingCache::Purge()
  783. {
  784. CLock lock( _mutex );
  785. _aItems.Clear();
  786. } //Purge