_monetary.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * Copyright (c) 1999
  3. * Silicon Graphics Computer Systems, Inc.
  4. *
  5. * Copyright (c) 1999
  6. * Boris Fomitchev
  7. *
  8. * This material is provided "as is", with absolutely no warranty expressed
  9. * or implied. Any use is at your own risk.
  10. *
  11. * Permission to use or copy this software for any purpose is hereby granted
  12. * without fee, provided the above notices are retained on all copies.
  13. * Permission to modify the code and to distribute modified code is granted,
  14. * provided the above notices are retained, and a notice that the code was
  15. * modified is included with the above copyright notice.
  16. *
  17. */
  18. #ifndef _STLP_MONETARY_C
  19. #define _STLP_MONETARY_C
  20. # ifndef _STLP_INTERNAL_MONETARY_H
  21. # include <stl/_monetary.h>
  22. # endif
  23. #ifndef _STLP_INTERNAL_IOS_H
  24. # include <stl/_ios.h>
  25. #endif
  26. #ifndef _STLP_INTERNAL_NUM_PUT_H
  27. # include <stl/_num_put.h>
  28. #endif
  29. #ifndef _STLP_INTERNAL_NUM_GET_H
  30. # include <stl/_num_get.h>
  31. #endif
  32. _STLP_BEGIN_NAMESPACE
  33. template <class _CharT, class _InputIterator>
  34. locale::id money_get<_CharT, _InputIterator>::id;
  35. template <class _CharT, class _OutputIterator>
  36. locale::id money_put<_CharT, _OutputIterator>::id;
  37. // money_get facets
  38. _STLP_MOVE_TO_PRIV_NAMESPACE
  39. // helper functions for do_get
  40. template <class _InIt1, class _InIt2>
  41. pair<_InIt1, bool> __get_string( _InIt1 __first, _InIt1 __last,
  42. _InIt2 __str_first, _InIt2 __str_last) {
  43. while ( __first != __last && __str_first != __str_last && *__first == *__str_first ) {
  44. ++__first;
  45. ++__str_first;
  46. }
  47. return make_pair(__first, __str_first == __str_last);
  48. }
  49. template <class _InIt, class _OuIt, class _CharT>
  50. bool
  51. __get_monetary_value(_InIt& __first, _InIt __last, _OuIt __out_ite,
  52. const ctype<_CharT>& _c_type,
  53. _CharT __point, int __frac_digits, _CharT __sep,
  54. const string& __grouping, bool &__syntax_ok) {
  55. if (__first == __last || !_c_type.is(ctype_base::digit, *__first))
  56. return false;
  57. char __group_sizes[128];
  58. char* __group_sizes_end = __grouping.empty()? 0 : __group_sizes;
  59. char __current_group_size = 0;
  60. while (__first != __last) {
  61. if (_c_type.is(ctype_base::digit, *__first)) {
  62. ++__current_group_size;
  63. *__out_ite++ = *__first++;
  64. }
  65. else if (__group_sizes_end) {
  66. if (*__first == __sep) {
  67. *__group_sizes_end++ = __current_group_size;
  68. __current_group_size = 0;
  69. ++__first;
  70. }
  71. else break;
  72. }
  73. else
  74. break;
  75. }
  76. if (__grouping.empty())
  77. __syntax_ok = true;
  78. else {
  79. if (__group_sizes_end != __group_sizes)
  80. *__group_sizes_end++ = __current_group_size;
  81. __syntax_ok = __valid_grouping(__group_sizes, __group_sizes_end,
  82. __grouping.data(), __grouping.data()+ __grouping.size());
  83. if (__first == __last || *__first != __point) {
  84. for (int __digits = 0; __digits != __frac_digits; ++__digits)
  85. *__out_ite++ = _CharT('0');
  86. return true; // OK not to have decimal point
  87. }
  88. }
  89. ++__first;
  90. int __digits = 0;
  91. while (__first != __last && _c_type.is(ctype_base::digit, *__first)) {
  92. *__out_ite++ = *__first++;
  93. ++__digits;
  94. }
  95. __syntax_ok = __syntax_ok && (__digits == __frac_digits);
  96. return true;
  97. }
  98. template <class _CharT, class _InputIter, class _StrType>
  99. _InputIter __money_do_get(_InputIter __s, _InputIter __end, bool __intl,
  100. ios_base& __str, ios_base::iostate& __err,
  101. _StrType& __digits, bool &__is_positive, _CharT* /*__dummy*/) {
  102. if (__s == __end) {
  103. __err |= ios_base::eofbit;
  104. return __s;
  105. }
  106. typedef _CharT char_type;
  107. typedef _StrType string_type;
  108. typedef _InputIter iter_type;
  109. typedef moneypunct<char_type, false> _Punct;
  110. typedef moneypunct<char_type, true> _Punct_intl;
  111. typedef ctype<char_type> _Ctype;
  112. locale __loc = __str.getloc();
  113. const _Punct& __punct = use_facet<_Punct>(__loc) ;
  114. const _Punct_intl& __punct_intl = use_facet<_Punct_intl>(__loc) ;
  115. const _Ctype& __c_type = use_facet<_Ctype>(__loc) ;
  116. money_base::pattern __format = __intl ? __punct_intl.neg_format()
  117. : __punct.neg_format();
  118. string_type __ns = __intl ? __punct_intl.negative_sign()
  119. : __punct.negative_sign();
  120. string_type __ps = __intl ? __punct_intl.positive_sign()
  121. : __punct.positive_sign();
  122. int __i;
  123. bool __symbol_required = (__str.flags() & ios_base::showbase) != 0;
  124. string_type __buf;
  125. back_insert_iterator<string_type> __out_ite(__buf);
  126. for (__i = 0; __i < 4; ++__i) {
  127. switch (__format.field[__i]) {
  128. case money_base::space:
  129. if (!__c_type.is(ctype_base::space, *__s)) {
  130. __err = ios_base::failbit;
  131. return __s;
  132. }
  133. ++__s;
  134. case money_base::none:
  135. while (__s != __end && __c_type.is(ctype_base::space, *__s))
  136. ++__s;
  137. break;
  138. case money_base::symbol: {
  139. string_type __curs = __intl ? __punct_intl.curr_symbol()
  140. : __punct.curr_symbol();
  141. pair<iter_type, bool>
  142. __result = __get_string(__s, __end, __curs.begin(), __curs.end());
  143. if (!__result.second && __symbol_required)
  144. __err = ios_base::failbit;
  145. __s = __result.first;
  146. break;
  147. }
  148. case money_base::sign: {
  149. if (__s == __end) {
  150. if (__ps.empty())
  151. break;
  152. if (__ns.empty()) {
  153. __is_positive = false;
  154. break;
  155. }
  156. __err = ios_base::failbit;
  157. return __s;
  158. }
  159. else {
  160. if (__ps.empty()) {
  161. if (__ns.empty())
  162. break;
  163. if (*__s == __ns[0]) {
  164. ++__s;
  165. __is_positive = false;
  166. }
  167. break;
  168. }
  169. else {
  170. if (*__s == __ps[0]) {
  171. ++__s;
  172. break;
  173. }
  174. if (__ns.empty())
  175. break;
  176. if (*__s == __ns[0]) {
  177. ++__s;
  178. __is_positive = false;
  179. break;
  180. }
  181. __err = ios_base::failbit;
  182. }
  183. }
  184. return __s;
  185. }
  186. case money_base::value: {
  187. char_type __point = __intl ? __punct_intl.decimal_point()
  188. : __punct.decimal_point();
  189. int __frac_digits = __intl ? __punct_intl.frac_digits()
  190. : __punct.frac_digits();
  191. string __grouping = __intl ? __punct_intl.grouping()
  192. : __punct.grouping();
  193. bool __syntax_ok = true;
  194. bool __result;
  195. char_type __sep = __grouping.empty() ? char_type() :
  196. __intl ? __punct_intl.thousands_sep() : __punct.thousands_sep();
  197. __result = __get_monetary_value(__s, __end, __out_ite, __c_type,
  198. __point, __frac_digits,
  199. __sep,
  200. __grouping, __syntax_ok);
  201. if (!__syntax_ok)
  202. __err |= ios_base::failbit;
  203. if (!__result) {
  204. __err = ios_base::failbit;
  205. return __s;
  206. }
  207. break;
  208. } // Close money_base::value case
  209. } // Close switch statement
  210. } // Close for loop
  211. if (__is_positive) {
  212. if (__ps.size() > 1) {
  213. pair<_InputIter, bool>
  214. __result = __get_string(__s, __end, __ps.begin() + 1, __ps.end());
  215. __s = __result.first;
  216. if (!__result.second)
  217. __err |= ios::failbit;
  218. }
  219. if (!(__err & ios_base::failbit))
  220. __digits = __buf;
  221. }
  222. else {
  223. if (__ns.size() > 1) {
  224. pair<_InputIter, bool>
  225. __result = __get_string(__s, __end, __ns.begin() + 1, __ns.end());
  226. __s = __result.first;
  227. if (!__result.second)
  228. __err |= ios::failbit;
  229. }
  230. if (!(__err & ios::failbit)) {
  231. __digits = __c_type.widen('-');
  232. __digits += __buf;
  233. }
  234. }
  235. if (__s == __end)
  236. __err |= ios::eofbit;
  237. return __s;
  238. }
  239. _STLP_MOVE_TO_STD_NAMESPACE
  240. //===== methods ======
  241. template <class _CharT, class _InputIter>
  242. _InputIter
  243. money_get<_CharT, _InputIter>::do_get(_InputIter __s, _InputIter __end, bool __intl,
  244. ios_base& __str, ios_base::iostate& __err,
  245. _STLP_LONGEST_FLOAT_TYPE& __units) const {
  246. string_type __buf;
  247. bool __is_positive = true;
  248. __s = _STLP_PRIV __money_do_get(__s, __end, __intl, __str, __err, __buf, __is_positive, (_CharT*)0);
  249. if (__err == ios_base::goodbit || __err == ios_base::eofbit) {
  250. typename string_type::iterator __b = __buf.begin(), __e = __buf.end();
  251. if (!__is_positive) ++__b;
  252. // Can't use atold, since it might be wchar_t. Don't get confused by name below :
  253. // it's perfectly capable of reading long double.
  254. _STLP_PRIV __get_decimal_integer(__b, __e, __units, (_CharT*)0);
  255. if (!__is_positive) {
  256. __units = -__units;
  257. }
  258. }
  259. return __s;
  260. }
  261. template <class _CharT, class _InputIter>
  262. _InputIter
  263. money_get<_CharT, _InputIter>::do_get(iter_type __s, iter_type __end, bool __intl,
  264. ios_base& __str, ios_base::iostate& __err,
  265. string_type& __digits) const {
  266. bool __is_positive = true;
  267. return _STLP_PRIV __money_do_get(__s, __end, __intl, __str, __err, __digits, __is_positive, (_CharT*)0);
  268. }
  269. // money_put facets
  270. _STLP_MOVE_TO_PRIV_NAMESPACE
  271. template <class _CharT, class _OutputIter, class _Str_Type, class _Str>
  272. _OutputIter __money_do_put(_OutputIter __s, bool __intl, ios_base& __str,
  273. _CharT __fill, const _Str& __digits, bool __check_digits,
  274. _Str_Type * /*__dummy*/) {
  275. typedef _CharT char_type;
  276. typedef _Str_Type string_type;
  277. typedef ctype<char_type> _Ctype;
  278. typedef moneypunct<char_type, false> _Punct;
  279. typedef moneypunct<char_type, true> _Punct_intl;
  280. locale __loc = __str.getloc();
  281. const _Ctype& __c_type = use_facet<_Ctype>(__loc) ;
  282. const _Punct& __punct = use_facet<_Punct>(__loc) ;
  283. const _Punct_intl& __punct_intl = use_facet<_Punct_intl>(__loc) ;
  284. // some special characters
  285. char_type __minus = __c_type.widen('-');
  286. char_type __plus = __c_type.widen('+');
  287. char_type __space = __c_type.widen(' ');
  288. char_type __zero = __c_type.widen('0');
  289. char_type __point = __intl ? __punct_intl.decimal_point()
  290. : __punct.decimal_point();
  291. char_type __sep = __intl ? __punct_intl.thousands_sep()
  292. : __punct.thousands_sep();
  293. string __grouping = __intl ? __punct_intl.grouping()
  294. : __punct.grouping();
  295. int __frac_digits = __intl ? __punct_intl.frac_digits()
  296. : __punct.frac_digits();
  297. string_type __curr_sym = __intl ? __punct_intl.curr_symbol()
  298. : __punct.curr_symbol();
  299. // if there are no digits we are going to return __s. If there
  300. // are digits, but not enough to fill the frac_digits, we are
  301. // going to add zeros. I don't know whether this is right or
  302. // not.
  303. if (__digits.empty())
  304. return __s;
  305. typename string_type::const_iterator __digits_first = __digits.begin();
  306. typename string_type::const_iterator __digits_last = __digits.end();
  307. bool __is_negative = *__digits_first == __minus;
  308. if (__is_negative)
  309. ++__digits_first;
  310. #if !defined (__BORLANDC__)
  311. string_type __sign = __intl ? __is_negative ? __punct_intl.negative_sign()
  312. : __punct_intl.positive_sign()
  313. : __is_negative ? __punct.negative_sign()
  314. : __punct.positive_sign();
  315. #else
  316. string_type __sign;
  317. if (__intl) {
  318. if (__is_negative)
  319. __sign = __punct_intl.negative_sign();
  320. else
  321. __sign = __punct_intl.positive_sign();
  322. }
  323. else {
  324. if (__is_negative)
  325. __sign = __punct.negative_sign();
  326. else
  327. __sign = __punct.positive_sign();
  328. }
  329. #endif
  330. if (__check_digits) {
  331. typename string_type::const_iterator __cp = __digits_first;
  332. while (__cp != __digits_last && __c_type.is(ctype_base::digit, *__cp))
  333. ++__cp;
  334. if (__cp == __digits_first)
  335. return __s;
  336. __digits_last = __cp;
  337. }
  338. // If grouping is required, we make a copy of __digits and
  339. // insert the grouping.
  340. _STLP_BASIC_IOSTRING(char_type) __new_digits;
  341. if (!__grouping.empty()) {
  342. __new_digits.assign(__digits_first, __digits_last);
  343. __insert_grouping(__new_digits,
  344. __new_digits.size() - __frac_digits,
  345. __grouping,
  346. __sep, __plus, __minus, 0);
  347. __digits_first = __new_digits.begin(); // <<--
  348. __digits_last = __new_digits.end(); // <<--
  349. }
  350. // Determine the amount of padding required, if any.
  351. streamsize __width = __str.width();
  352. #if defined (_STLP_DEBUG) && (defined(__HP_aCC) && (__HP_aCC <= 1))
  353. size_t __value_length = operator -(__digits_last, __digits_first);
  354. #else
  355. size_t __value_length = __digits_last - __digits_first;
  356. #endif
  357. size_t __length = __value_length + __sign.size();
  358. if (__frac_digits != 0)
  359. ++__length;
  360. bool __generate_curr = (__str.flags() & ios_base::showbase) !=0;
  361. if (__generate_curr)
  362. __length += __curr_sym.size();
  363. money_base::pattern __format = __intl ? (__is_negative ? __punct_intl.neg_format()
  364. : __punct_intl.pos_format())
  365. : (__is_negative ? __punct.neg_format()
  366. : __punct.pos_format());
  367. {
  368. //For the moment the following is commented for decoding reason.
  369. //No reason to add a space last if the money symbol do not have to be display
  370. //if (__format.field[3] == (char) money_base::symbol && !__generate_curr) {
  371. // if (__format.field[2] == (char) money_base::space) {
  372. // __format.field[2] = (char) money_base::none;
  373. // }
  374. //}
  375. //space can only be second or third and only once (22.2.6.3-1):
  376. if ((__format.field[1] == (char) money_base::space) ||
  377. (__format.field[2] == (char) money_base::space))
  378. ++__length;
  379. }
  380. const bool __need_fill = (((sizeof(streamsize) > sizeof(size_t)) && (__STATIC_CAST(streamsize, __length) < __width)) ||
  381. ((sizeof(streamsize) <= sizeof(size_t)) && (__length < __STATIC_CAST(size_t, __width))));
  382. streamsize __fill_amt = __need_fill ? __width - __length : 0;
  383. ios_base::fmtflags __fill_pos = __str.flags() & ios_base::adjustfield;
  384. if (__fill_amt != 0 &&
  385. !(__fill_pos & (ios_base::left | ios_base::internal)))
  386. __s = _STLP_PRIV __fill_n(__s, __fill_amt, __fill);
  387. for (int __i = 0; __i < 4; ++__i) {
  388. char __ffield = __format.field[__i];
  389. switch (__ffield) {
  390. case money_base::space:
  391. *__s++ = __space;
  392. case money_base::none:
  393. if (__fill_amt != 0 && __fill_pos == ios_base::internal)
  394. __s = _STLP_PRIV __fill_n(__s, __fill_amt, __fill);
  395. break;
  396. case money_base::symbol:
  397. if (__generate_curr)
  398. __s = _STLP_STD::copy(__curr_sym.begin(), __curr_sym.end(), __s);
  399. break;
  400. case money_base::sign:
  401. if (!__sign.empty())
  402. *__s++ = __sign[0];
  403. break;
  404. case money_base::value:
  405. if (__frac_digits == 0) {
  406. __s = _STLP_STD::copy(__digits_first, __digits_last, __s);
  407. } else {
  408. if ((int)__value_length <= __frac_digits) {
  409. // if we see '9' here, we should out 0.09
  410. *__s++ = __zero; // integer part is zero
  411. *__s++ = __point; // decimal point
  412. __s = _STLP_PRIV __fill_n(__s, __frac_digits - __value_length, __zero); // zeros
  413. __s = _STLP_STD::copy(__digits_first, __digits_last, __s); // digits
  414. } else {
  415. __s = _STLP_STD::copy(__digits_first, __digits_last - __frac_digits, __s);
  416. if (__frac_digits != 0) {
  417. *__s++ = __point;
  418. __s = _STLP_STD::copy(__digits_last - __frac_digits, __digits_last, __s);
  419. }
  420. }
  421. }
  422. break;
  423. } //Close for switch
  424. } // Close for loop
  425. // Ouput rest of sign if necessary.
  426. if (__sign.size() > 1)
  427. __s = _STLP_STD::copy(__sign.begin() + 1, __sign.end(), __s);
  428. if (__fill_amt != 0 &&
  429. !(__fill_pos & (ios_base::right | ios_base::internal)))
  430. __s = _STLP_PRIV __fill_n(__s, __fill_amt, __fill);
  431. return __s;
  432. }
  433. _STLP_MOVE_TO_STD_NAMESPACE
  434. template <class _CharT, class _OutputIter>
  435. _OutputIter
  436. money_put<_CharT, _OutputIter>
  437. ::do_put(_OutputIter __s, bool __intl, ios_base& __str,
  438. char_type __fill, _STLP_LONGEST_FLOAT_TYPE __units) const {
  439. _STLP_BASIC_IOSTRING(char_type) __digits;
  440. _STLP_PRIV __get_money_digits(__digits, __str, __units);
  441. return _STLP_PRIV __money_do_put(__s, __intl, __str, __fill, __digits, false, __STATIC_CAST(string_type*, 0));
  442. }
  443. template <class _CharT, class _OutputIter>
  444. _OutputIter
  445. money_put<_CharT, _OutputIter>
  446. ::do_put(_OutputIter __s, bool __intl, ios_base& __str,
  447. char_type __fill, const string_type& __digits) const {
  448. return _STLP_PRIV __money_do_put(__s, __intl, __str, __fill, __digits, true, __STATIC_CAST(string_type*, 0));
  449. }
  450. _STLP_END_NAMESPACE
  451. #endif /* _STLP_MONETARY_C */
  452. // Local Variables:
  453. // mode:C++
  454. // End: