blob: 1b1d1d562f985352749bba56a0e2f0d65d3973f5 [file] [log] [blame]
/***************************************************************************
*
* _money_put.cc - definition of std::num_put members
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you 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.
*
* Copyright 1994-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#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 (std) {
template <class _CharT, class _OutputIter>
_RW::__rw_facet_id money_put<_CharT, _OutputIter>::id;
// outlined to avoid generating a vtable in each translation unit
// that uses the class
template <class _CharT, class _OutputIter>
/* virtual */ money_put<_CharT, _OutputIter>::
~money_put () /* nothrow */
{
// no-op
}
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;
#ifdef __GNUG__
// silence bogus gcc -Wuninitialized warning:
// object may be used uninitialized in this function
// while avoiding bogus HP aCC/cadvise warning 20200:
// potential null pointer dereference
__pun0 = 0;
__pun1 = 0;
#endif // gcc
if (__intl) {
__pun1 = &_RWSTD_USE_FACET (_Punct1, __flags.getloc ());
}
else {
__pun0 = &_RWSTD_USE_FACET (_Punct0, __flags.getloc ());
}
const ctype<_CharT> &__ctp =
_RWSTD_USE_FACET (ctype<_CharT>,__flags.getloc ());
const char __signchar = __ctp.narrow (*__s, '\0');
money_base::pattern __fmat; // negative or positive format
string_type __sign; // negative or positive sign
if ('-' == __signchar) {
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 ('+' == __signchar) {
++__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 = _RWSTD_USE_FACET (_Punct, __flags.getloc ());
__fd = __pun.frac_digits ();
__grouping = __pun.grouping ();
}
else {
typedef moneypunct<_CharT, false> _Punct;
const _Punct &__pun = _RWSTD_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 =
_RWSTD_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 = _RWSTD_USE_FACET (_Punct, __flags.getloc ());
__fd = __pun.frac_digits ();
__grouping = __pun.grouping ();
}
else {
typedef moneypunct<_CharT, false> _Punct;
const _Punct &__pun = _RWSTD_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 =
_RWSTD_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 std