text: /***************************************************************************
   *
   * _money_put.cc - definition of std::num_put members
   *
   * $Id$
   *
   ***************************************************************************
   *
   * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
   * Software division. Licensed under the Apache License, Version 2.0 (the
   * "License");  you may  not use this file except  in compliance with the
   * License.    You    may   obtain   a   copy   of    the   License    at
   * http://www.apache.org/licenses/LICENSE-2.0.    Unless   required    by
   * applicable law  or agreed to  in writing,  software  distributed under
   * the License is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR
   * CONDITIONS OF  ANY KIND, either  express or implied.  See  the License
   * for the specific language governing permissions  and limitations under
   * the License.
   * 
   **************************************************************************/
  
  #include <streambuf>
  #include <loc/_moneypunct.h>
  #include <loc/_ctype.h>
  
  
  _RWSTD_NAMESPACE (__rw) {
  
  _RWSTD_EXPORT _RWSTD_SIZE_T
  __rw_put_num (char**, _RWSTD_SIZE_T, unsigned, int, _RWSTD_STREAMSIZE,
                const void*, const char*);
  
  _RWSTD_EXPORT _RWSTD_SIZE_T
  __rw_put_groups (char **, _RWSTD_SIZE_T, _RWSTD_SIZE_T,
                   const char*, const char*);
  
  }   // namespace __rw
  
  
  _RWSTD_NAMESPACE (_V3_LOCALE) { 
  
  
  template <class _CharT, class _OutputIter>
  _RW::__rw_facet_id money_put<_CharT, _OutputIter>::id;
  
  
  template <class _CharT, class _OutputIter>
  /* private */ _TYPENAME money_put<_CharT, _OutputIter>::iter_type
  money_put<_CharT, _OutputIter>::
  _C_put (iter_type __it, int __opts, ios_base &__flags, char_type __fill,
          const char_type *__s, _RWSTD_SIZE_T __n, int __fd,
          const char *__groups, _RWSTD_SIZE_T __ngroups) const
  {
      // static const arrays of pointers to moneypunct<charT, Intl> members
      // to avoid "if (intl)" conditionals when retrieving punct values
  
      const bool __intl = 0 != (__opts & _C_intl);
      const bool __num  = 0 != (__opts & _C_ldbl);
  
      typedef moneypunct<_CharT, false> _Punct0;
      typedef moneypunct<_CharT, true>  _Punct1;
  
      const _Punct0* __pun0;
      const _Punct1* __pun1;
  
      if (__intl) {
          __pun0 = 0;
          __pun1 = &_V3_USE_FACET (_Punct1, __flags.getloc ());
      }
      else {
          __pun0 = &_V3_USE_FACET (_Punct0, __flags.getloc ());
          __pun1 = 0;
      }
  
      const ctype<_CharT> &__ctp =
          _V3_USE_FACET (ctype<_CharT>,__flags.getloc ());
  
      money_base::pattern __fmat;   // negative or positive format
      string_type         __sign;   // negative or positive sign
  
      if ('-' == __ctp.narrow (*__s, '\0')) {
          if (__intl) {
              __fmat = __pun1->neg_format ();
              __sign = __pun1->negative_sign ();
          }
          else {
              __fmat = __pun0->neg_format ();
              __sign = __pun0->negative_sign ();
          }
          ++__s;
          --__n;
      }
      else {
          if (__intl) {
              __fmat = __pun1->pos_format ();
              __sign = __pun1->positive_sign ();
          }
          else {
              __fmat = __pun0->pos_format ();
              __sign = __pun0->positive_sign ();
          }
          if ('+' == __ctp.narrow (*__s, '\0')) {
              ++__s;
              --__n;
          }
      }
  
      // optional currency sumbol
      const string_type __curr = (__flags.flags () & _RWSTD_IOS_SHOWBASE) ?
            __intl ? __pun1->curr_symbol () : __pun0->curr_symbol ()
          : string_type ();
  
      // size of fractional and integral parts, respectively, to output
      long __dint = long (__n - __fd);
  
      // must have at least one group (even if there are no thousands_sep)
      _RWSTD_ASSERT (__ngroups > 0);
  
      // adjust padding by the sizes of each component, including the
      // number of thousands separators to be inserted
      long __pad = long (
            __flags.width () - __curr.size () - __sign.size ()
          - !__dint - !!__fd - (__dint > 0 ? __dint : -__dint) - __fd
          - (   money_base::space == __fmat.field [1]
             || money_base::space == __fmat.field [2])
          - (__ngroups - 1));
  
      const int __adj = __flags.flags () & _RWSTD_IOS_ADJUSTFIELD;
  
      if (__adj != _RWSTD_IOS_INTERNAL && __adj != _RWSTD_IOS_LEFT) {
  
          for (; __pad > 0; --__pad, ++__it)
              *__it = __fill;
      }
  
      for (_RWSTD_SIZE_T __i = 0, __j; __i != sizeof __fmat; ++__i) {
  
          switch (__fmat.field [__i]) {
  
          case money_base::symbol:   // exactly one occurrence required
              for (__j = 0; __j != __curr.size (); ++__j, ++__it)
                  *__it = __curr [__j];
              break;
  
          case money_base::sign:   // exactly one occurrence required
              if (__sign.size ()) {
                  // first character of sign only
                  *__it = __sign [0];
                  ++__it;
              }
              break;
  
          case money_base::space:   // optional (required if none not present)
              // 22.2.6.3, p1: the value space, if present,
              //               is neither first nor last.
  
              _RWSTD_REQUIRES (0 != __i && sizeof __fmat != __i - 1,
                               (_RWSTD_ERROR_RUNTIME_ERROR,
                                _RWSTD_FUNC ("std::num_put<>::do_put()")));
  
              // an ordinary space, not `fill', is required here
              // will precede any required padding
              *__it = __ctp.widen (' ');
              ++__it;
  
          case money_base::none:   // optional (required if space not present)
              // 22.2.6.3, p1: the value none, if present, is not first
  
              _RWSTD_REQUIRES (0 != __i,
                               (_RWSTD_ERROR_RUNTIME_ERROR,
                                _RWSTD_FUNC ("std::num_put<>::do_put()")));
  
              if (   (__adj & _RWSTD_IOS_ADJUSTFIELD) == _RWSTD_IOS_INTERNAL
                  && sizeof __fmat != __i - 1)
                  for (; __pad > 0; --__pad, ++__it)
                      *__it = __fill;
  
              break;
  
          case money_base::value: {   // exactly one occurrence required
  
              if (__dint < 0 || 0 == __dint && __fd > 0) {
                  const char_type __zero = __ctp.widen ('0');
  
                  // insert leading zero and decimal point
                  *__it = __zero;
                  ++__it;
  
                  *__it = __intl ?
                      __pun1->decimal_point () : __pun0->decimal_point ();
                  ++__it;
  
                  // insert leading fractional zeros
                  for (; __dint++; ++__it)
                      *__it = __zero;
  
                  // prevent insertion of the decimal point below
                  __dint = -1;
              }
  
              _RWSTD_SIZE_T __grplen = 0;
  
              for (const char_type *__e = __s + __n; __s != __e; ++__it, ++__s) {
  
                  if (!__num && !__ctp.is (ctype_base::digit, *__s))
                      break;
  
                  typedef unsigned char _UChar;
  
                  if (0 < __dint) {
  
                      _RWSTD_ASSERT (0 != __groups);
  
                      if (*__groups && __grplen == _UChar (*__groups)) {
                          *__it = __intl ? __pun1->thousands_sep ()
                                         : __pun0->thousands_sep ();
                          __grplen = 0;
                          ++__groups;
                          ++__it;
                      }
                  }
                  else if (0 == __dint) {
                      *__it = __intl ? __pun1->decimal_point ()
                                     : __pun0->decimal_point ();
                      ++__it;
                  }
  
                  --__dint;
                  ++__grplen;
  
                  switch (*__s) {
                      // replace either the period or the comma with the
                      // decimal point in case a setlocale() call made by
                      // the program changed the default '.' to ','
                  case '.':
                  case ',':
                      *__it = __intl ? __pun1->decimal_point ()
                                     : __pun0->decimal_point ();
                      break;
  
                  case ';':
                      *__it = __intl ? __pun1->thousands_sep ()
                                     : __pun0->thousands_sep ();
                      break;
  
                  default:  *__it = *__s;
                  }
              }
  
              break;
          }
          }
      }
  
      // output the remaining characters of sign (if any)
      for (_RWSTD_SIZE_T __k = 1; __k < __sign.size (); ++__k, ++__it)
          *__it = __sign [__k];
  
      // left ajustment
      for (; __pad > 0; --__pad, ++__it)
          *__it = __fill;
  
      // 22.2.6.2.2, p1: reset width()
      __flags.width (0);
  
      return __it;
  }
  
  
  template <class _CharT, class _OutputIter>
  /* virtual */ _TYPENAME money_put<_CharT, _OutputIter>::iter_type
  money_put<_CharT, _OutputIter>::
  do_put (iter_type __i, bool __intl, ios_base &__flags, char_type __fill,
          long double __val) const
  {
      int __fd;
      string __grouping;
  
      if (__intl) {
          typedef moneypunct<_CharT, true> _Punct;
          const _Punct &__pun = _V3_USE_FACET (_Punct, __flags.getloc ());
  
          __fd       = __pun.frac_digits ();
          __grouping = __pun.grouping ();
      }
      else {
          typedef moneypunct<_CharT, false> _Punct;
          const _Punct &__pun = _V3_USE_FACET (_Punct, __flags.getloc ());
  
          __fd       = __pun.frac_digits ();
          __grouping = __pun.grouping ();
      }
  
      char       __buf [304];
      char_type __wbuf [sizeof __buf];
  
      char *__pbuf = __buf;
  
      // format a floating point number in fixed precision into narrow buffer
      // will insert thousands_sep placeholders (';') accroding to grouping
      const _RWSTD_SIZE_T __n =
          _RW::__rw_put_num (&__pbuf, sizeof __buf, _RWSTD_IOS_FIXED,
                             _C_ldouble | _C_ptr,
                             _RWSTD_STATIC_CAST (_RWSTD_STREAMSIZE, -__fd),
                             &__val, __grouping.c_str ());
  
      // widen narrow buffer (necessary even if char_type == char)
      const ctype<_CharT> &__ctp =
          _V3_USE_FACET (ctype<_CharT>, __flags.getloc ());
  
      __ctp.widen (__buf, __buf + __n, __wbuf);
  
      // write the widened buffer out, replacing any commas
      // with the actual thousands_sep punct character
      return _C_put (__i, (__intl ? _C_intl : 0) | _C_ldbl,
                     __flags, __fill, __wbuf, __n, 0, "", 1);
  }
  
  
  template <class _CharT, class _OutputIter>
  /* virtual */ _TYPENAME money_put<_CharT, _OutputIter>::iter_type
  money_put<_CharT, _OutputIter>::
  do_put (iter_type __i, bool __intl, ios_base &__flags, char_type __fill,
          const string_type &__str) const
  {
      // fractional part does not undergo grouping and will be removed
      int __fd;
  
      string __grouping;
  
      if (__intl) {
          typedef moneypunct<_CharT, true> _Punct;
  
          const _Punct &__pun = _V3_USE_FACET (_Punct, __flags.getloc ());
  
          __fd       = __pun.frac_digits ();
          __grouping = __pun.grouping ();
      }
      else {
          typedef moneypunct<_CharT, false> _Punct;
  
          const _Punct &__pun = _V3_USE_FACET (_Punct, __flags.getloc ());
  
          __fd       = __pun.frac_digits ();
          __grouping = __pun.grouping ();
      }
  
      _RWSTD_SIZE_T  __ngroups = 1;          // always at least one group
      _RWSTD_SIZE_T  __strdigs = 0;          // number of digits in `str'
  
      typedef string::traits_type                   _Traits;
      typedef _TYPENAME string_type::const_iterator _StringIter;
  
      char        __buf [304];            // buffer for groups
      static char __nul    = '\0';        // `groups' must be non-0
      char       *__groups = __grouping.size () ? __buf : &__nul;
  
      const ctype<_CharT> &__ctp =
          _V3_USE_FACET (ctype<_CharT>, __flags.getloc ());
  
      // narrow digits into a temporary buffer to determine grouping
      for (_StringIter __it = __str.begin (); __it != __str.end (); ++__it) {
          if (__ctp.is (ctype_base::digit, *__it)) {
              if (__groups != &__nul)
                  _Traits::assign (*__groups++, __ctp.narrow (*__it, '\0'));
          }
          else if (__str.begin () != __it || '-' != __ctp.narrow (*__it, '\0'))
              break;
          ++__strdigs;
      }
  
      if (__groups != &__nul && __fd >= 0 && __fd < __groups - __buf) {
          __groups -= __fd;
  
          // compute the size of each group relative to the formatted number
          // e.g., with `str' of "9876543210" and `grouping' of "\1\2\3",
          // `groups' will point at "\1\3\3\2\1" since `str' will be
          // formatted as "9,876,543,21,0" with thousands_sep's inserted
  
          char *__pbuf = __buf;
  
          *__pbuf = '\0';
  
          __ngroups =
              _RW::__rw_put_groups (&__pbuf, __groups - __pbuf, sizeof __buf,
                                    0, __grouping.c_str ());
          __pbuf [__ngroups] = '\0';
          __groups           = __pbuf;
      }
  
      return _C_put (__i, __intl ? _C_intl : 0,
                     __flags, __fill, __str.c_str (), __strdigs,
                     __fd, __groups, __ngroups);
  }
  
  
  }   // namespace _V3_LOCALE
  