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_NUM_PUT_C
19#define _STLP_NUM_PUT_C
20
21#ifndef _STLP_INTERNAL_NUM_PUT_H
22#  include <stl/_num_put.h>
23#endif
24
25#ifndef _STLP_INTERNAL_LIMITS
26#  include <stl/_limits.h>
27#endif
28
29_STLP_BEGIN_NAMESPACE
30
31_STLP_MOVE_TO_PRIV_NAMESPACE
32
33// __do_put_float and its helper functions.  Strategy: write the output
34// to a buffer of char, transform the buffer to _CharT, and then copy
35// it to the output.
36
37//----------------------------------------------------------------------
38// num_put facet
39
40template <class _CharT, class _OutputIter>
41_OutputIter  _STLP_CALL
42__copy_float_and_fill(const _CharT* __first, const _CharT* __last,
43                      _OutputIter __oi,
44                      ios_base::fmtflags __flags,
45                      streamsize __width, _CharT __fill,
46                      _CharT __xplus, _CharT __xminus) {
47  if (__width <= __last - __first)
48    return _STLP_STD::copy(__first, __last, __oi);
49  else {
50    streamsize __pad = __width - (__last - __first);
51    ios_base::fmtflags __dir = __flags & ios_base::adjustfield;
52
53    if (__dir == ios_base::left) {
54      __oi = _STLP_STD::copy(__first, __last, __oi);
55      return _STLP_PRIV __fill_n(__oi, __pad, __fill);
56    }
57    else if (__dir == ios_base::internal && __first != __last &&
58             (*__first == __xplus || *__first == __xminus)) {
59      *__oi++ = *__first++;
60      __oi = _STLP_PRIV __fill_n(__oi, __pad, __fill);
61      return _STLP_STD::copy(__first, __last, __oi);
62    }
63    else {
64      __oi = _STLP_PRIV __fill_n(__oi, __pad, __fill);
65      return _STLP_STD::copy(__first, __last, __oi);
66    }
67  }
68}
69
70#if !defined (_STLP_NO_WCHAR_T)
71// Helper routine for wchar_t
72template <class _OutputIter>
73_OutputIter  _STLP_CALL
74__put_float(__iostring &__str, _OutputIter __oi,
75            ios_base& __f, wchar_t __fill,
76            wchar_t __decimal_point, wchar_t __sep,
77            size_t __group_pos, const string& __grouping) {
78  const ctype<wchar_t>& __ct = use_facet<ctype<wchar_t> >(__f.getloc());
79
80  __iowstring __wbuf;
81  __convert_float_buffer(__str, __wbuf, __ct, __decimal_point);
82
83  if (!__grouping.empty()) {
84    __insert_grouping(__wbuf, __group_pos, __grouping,
85                      __sep, __ct.widen('+'), __ct.widen('-'), 0);
86  }
87
88  return __copy_float_and_fill(__wbuf.data(), __wbuf.data() + __wbuf.size(), __oi,
89                               __f.flags(), __f.width(0), __fill, __ct.widen('+'), __ct.widen('-'));
90}
91#endif /* WCHAR_T */
92
93// Helper routine for char
94template <class _OutputIter>
95_OutputIter  _STLP_CALL
96__put_float(__iostring &__str, _OutputIter __oi,
97            ios_base& __f, char __fill,
98            char __decimal_point, char __sep,
99            size_t __group_pos, const string& __grouping) {
100  if ((__group_pos < __str.size()) && (__str[__group_pos] == '.')) {
101    __str[__group_pos] = __decimal_point;
102  }
103
104  if (!__grouping.empty()) {
105    __insert_grouping(__str, __group_pos,
106                      __grouping, __sep, '+', '-', 0);
107  }
108
109  return __copy_float_and_fill(__str.data(), __str.data() + __str.size(), __oi,
110                               __f.flags(), __f.width(0), __fill, '+', '-');
111}
112
113template <class _CharT, class _OutputIter, class _Float>
114_OutputIter _STLP_CALL
115__do_put_float(_OutputIter __s, ios_base& __f,
116                _CharT __fill, _Float __x) {
117  __iostring __buf;
118
119  size_t __group_pos = __write_float(__buf, __f.flags(), (int)__f.precision(), __x);
120
121  const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__f.getloc());
122  return __put_float(__buf, __s, __f, __fill,
123                     __np.decimal_point(), __np.thousands_sep(),
124                     __group_pos, __np.grouping());
125}
126
127inline void __get_money_digits_aux (__iostring &__buf, ios_base &, _STLP_LONGEST_FLOAT_TYPE __x)
128{ __get_floor_digits(__buf, __x); }
129
130#if !defined (_STLP_NO_WCHAR_T)
131inline void __get_money_digits_aux (__iowstring &__wbuf, ios_base &__f, _STLP_LONGEST_FLOAT_TYPE __x) {
132  __iostring __buf;
133  __get_floor_digits(__buf, __x);
134
135  const ctype<wchar_t>& __ct = use_facet<ctype<wchar_t> >(__f.getloc());
136  __convert_float_buffer(__buf, __wbuf, __ct, wchar_t(0), false);
137}
138#endif
139
140template <class _CharT>
141void _STLP_CALL __get_money_digits(_STLP_BASIC_IOSTRING(_CharT) &__buf, ios_base& __f, _STLP_LONGEST_FLOAT_TYPE __x)
142{ __get_money_digits_aux(__buf, __f, __x); }
143
144// _M_do_put_integer and its helper functions.
145
146template <class _CharT, class _OutputIter>
147_OutputIter _STLP_CALL
148__copy_integer_and_fill(const _CharT* __buf, ptrdiff_t __len,
149                        _OutputIter __oi,
150                        ios_base::fmtflags __flg, streamsize __wid, _CharT __fill,
151                        _CharT __xplus, _CharT __xminus) {
152  if (__len >= __wid)
153    return _STLP_STD::copy(__buf, __buf + __len, __oi);
154  else {
155    //casting numeric_limits<ptrdiff_t>::max to streamsize only works is ptrdiff_t is signed or streamsize representation
156    //is larger than ptrdiff_t one.
157    _STLP_STATIC_ASSERT((sizeof(streamsize) > sizeof(ptrdiff_t)) ||
158                        ((sizeof(streamsize) == sizeof(ptrdiff_t)) && numeric_limits<ptrdiff_t>::is_signed))
159    ptrdiff_t __pad = __STATIC_CAST(ptrdiff_t, (min) (__STATIC_CAST(streamsize, (numeric_limits<ptrdiff_t>::max)()),
160                                                      __STATIC_CAST(streamsize, __wid - __len)));
161    ios_base::fmtflags __dir = __flg & ios_base::adjustfield;
162
163    if (__dir == ios_base::left) {
164      __oi = _STLP_STD::copy(__buf, __buf + __len, __oi);
165      return _STLP_PRIV __fill_n(__oi, __pad, __fill);
166    }
167    else if (__dir == ios_base::internal && __len != 0 &&
168             (__buf[0] == __xplus || __buf[0] == __xminus)) {
169      *__oi++ = __buf[0];
170      __oi = __fill_n(__oi, __pad, __fill);
171      return _STLP_STD::copy(__buf + 1, __buf + __len, __oi);
172    }
173    else if (__dir == ios_base::internal && __len >= 2 &&
174             (__flg & ios_base::showbase) &&
175             (__flg & ios_base::basefield) == ios_base::hex) {
176      *__oi++ = __buf[0];
177      *__oi++ = __buf[1];
178      __oi = __fill_n(__oi, __pad, __fill);
179      return _STLP_STD::copy(__buf + 2, __buf + __len, __oi);
180    }
181    else {
182      __oi = __fill_n(__oi, __pad, __fill);
183      return _STLP_STD::copy(__buf, __buf + __len, __oi);
184    }
185  }
186}
187
188#if !defined (_STLP_NO_WCHAR_T)
189// Helper function for wchar_t
190template <class _OutputIter>
191_OutputIter _STLP_CALL
192__put_integer(char* __buf, char* __iend, _OutputIter __s,
193              ios_base& __f,
194              ios_base::fmtflags __flags, wchar_t __fill) {
195  locale __loc = __f.getloc();
196  const ctype<wchar_t>& __ct = use_facet<ctype<wchar_t> >(__loc);
197
198  wchar_t __xplus  = __ct.widen('+');
199  wchar_t __xminus = __ct.widen('-');
200
201  wchar_t __wbuf[64];
202  __ct.widen(__buf, __iend, __wbuf);
203  ptrdiff_t __len = __iend - __buf;
204  wchar_t* __eend = __wbuf + __len;
205
206  const numpunct<wchar_t>& __np = use_facet<numpunct<wchar_t> >(__loc);
207  const string& __grouping = __np.grouping();
208
209  if (!__grouping.empty()) {
210    int __basechars;
211    if (__flags & ios_base::showbase)
212      switch (__flags & ios_base::basefield) {
213        case ios_base::hex: __basechars = 2; break;
214        case ios_base::oct: __basechars = 1; break;
215        default: __basechars = 0;
216      }
217    else
218      __basechars = 0;
219
220    __len = __insert_grouping(__wbuf, __eend, __grouping, __np.thousands_sep(),
221                              __xplus, __xminus, __basechars);
222  }
223
224  return __copy_integer_and_fill((wchar_t*)__wbuf, __len, __s,
225                                 __flags, __f.width(0), __fill, __xplus, __xminus);
226}
227#endif
228
229// Helper function for char
230template <class _OutputIter>
231_OutputIter _STLP_CALL
232__put_integer(char* __buf, char* __iend, _OutputIter __s,
233              ios_base& __f, ios_base::fmtflags __flags, char __fill) {
234  char __grpbuf[64];
235  ptrdiff_t __len = __iend - __buf;
236
237  const numpunct<char>& __np = use_facet<numpunct<char> >(__f.getloc());
238  const string& __grouping = __np.grouping();
239
240  if (!__grouping.empty()) {
241    int __basechars;
242    if (__flags & ios_base::showbase)
243      switch (__flags & ios_base::basefield) {
244        case ios_base::hex: __basechars = 2; break;
245        case ios_base::oct: __basechars = 1; break;
246        default: __basechars = 0;
247      }
248    else
249      __basechars = 0;
250
251     // make sure there is room at the end of the buffer
252     // we pass to __insert_grouping
253    _STLP_STD::copy(__buf, __iend, (char *) __grpbuf);
254    __buf = __grpbuf;
255    __iend = __grpbuf + __len;
256    __len = __insert_grouping(__buf, __iend, __grouping, __np.thousands_sep(),
257                              '+', '-', __basechars);
258  }
259
260  return __copy_integer_and_fill(__buf, __len, __s, __flags, __f.width(0), __fill, '+', '-');
261}
262
263#if defined (_STLP_LONG_LONG)
264typedef _STLP_LONG_LONG __max_int_t;
265typedef unsigned _STLP_LONG_LONG __umax_int_t;
266#else
267typedef long __max_int_t;
268typedef unsigned long __umax_int_t;
269#endif
270
271_STLP_DECLSPEC const char* _STLP_CALL __hex_char_table_lo();
272_STLP_DECLSPEC const char* _STLP_CALL __hex_char_table_hi();
273
274template <class _Integer>
275inline char* _STLP_CALL
276__write_decimal_backward(char* __ptr, _Integer __x, ios_base::fmtflags __flags, const __true_type& /* is_signed */) {
277  const bool __negative = __x < 0 ;
278  __max_int_t __temp = __x;
279  __umax_int_t __utemp = __negative?-__temp:__temp;
280
281  for (; __utemp != 0; __utemp /= 10)
282    *--__ptr = (char)((int)(__utemp % 10) + '0');
283  // put sign if needed or requested
284  if (__negative)
285    *--__ptr = '-';
286  else if (__flags & ios_base::showpos)
287    *--__ptr = '+';
288  return __ptr;
289}
290
291template <class _Integer>
292inline char* _STLP_CALL
293__write_decimal_backward(char* __ptr, _Integer __x, ios_base::fmtflags __flags, const __false_type& /* is_signed */) {
294  for (; __x != 0; __x /= 10)
295    *--__ptr = (char)((int)(__x % 10) + '0');
296  // put sign if requested
297  if (__flags & ios_base::showpos)
298    *--__ptr = '+';
299  return __ptr;
300}
301
302template <class _Integer>
303char* _STLP_CALL
304__write_integer_backward(char* __buf, ios_base::fmtflags __flags, _Integer __x) {
305  char* __ptr = __buf;
306
307  if (__x == 0) {
308    *--__ptr = '0';
309    if ((__flags & ios_base::showpos) && ((__flags & (ios_base::oct | ios_base::hex)) == 0))
310      *--__ptr = '+';
311    // oct or hex base shall not be added to the 0 value (see '#' flag in C formating strings)
312  }
313  else {
314    switch (__flags & ios_base::basefield) {
315      case ios_base::oct:
316        {
317          __umax_int_t __temp = __x;
318          // if the size of integer is less than 8, clear upper part
319          if ( sizeof(__x) < 8  && sizeof(__umax_int_t) >= 8 )
320            __temp &= 0xFFFFFFFF;
321
322          for (; __temp != 0; __temp >>=3)
323            *--__ptr = (char)((((unsigned)__temp)& 0x7) + '0');
324
325          // put leading '0' if showbase is set
326          if (__flags & ios_base::showbase)
327            *--__ptr = '0';
328        }
329        break;
330      case ios_base::hex:
331        {
332          const char* __table_ptr = (__flags & ios_base::uppercase) ?
333            __hex_char_table_hi() : __hex_char_table_lo();
334          __umax_int_t __temp = __x;
335          // if the size of integer is less than 8, clear upper part
336          if ( sizeof(__x) < 8  && sizeof(__umax_int_t) >= 8 )
337            __temp &= 0xFFFFFFFF;
338
339          for (; __temp != 0; __temp >>=4)
340            *--__ptr = __table_ptr[((unsigned)__temp & 0xF)];
341
342          if (__flags & ios_base::showbase) {
343            *--__ptr = __table_ptr[16];
344            *--__ptr = '0';
345          }
346        }
347        break;
348      //case ios_base::dec:
349      default:
350        {
351#if defined(__HP_aCC) && (__HP_aCC == 1)
352          bool _IsSigned = !((_Integer)-1 > 0);
353          if (_IsSigned)
354            __ptr = __write_decimal_backward(__ptr, __x, __flags, __true_type() );
355          else
356            __ptr = __write_decimal_backward(__ptr, __x, __flags, __false_type() );
357#else
358          typedef typename __bool2type<numeric_limits<_Integer>::is_signed>::_Ret _IsSigned;
359          __ptr = __write_decimal_backward(__ptr, __x, __flags, _IsSigned());
360#endif
361        }
362        break;
363    }
364  }
365
366  // return pointer to beginning of the string
367  return __ptr;
368}
369
370template <class _CharT, class _OutputIter, class _Integer>
371_OutputIter _STLP_CALL
372__do_put_integer(_OutputIter __s, ios_base& __f, _CharT __fill, _Integer __x) {
373  // buffer size = number of bytes * number of digit necessary in the smallest Standard base (base 8, 3 digits/byte)
374  //               plus the longest base representation '0x'
375  // Do not use __buf_size to define __buf static buffer, some compilers (HP aCC) do not accept const variable as
376  // the specification of a static buffer size.
377  char __buf[sizeof(_Integer) * 3 + 2];
378  const ptrdiff_t __buf_size = sizeof(__buf) / sizeof(char);
379  ios_base::fmtflags __flags = __f.flags();
380  char* __ibeg = __write_integer_backward((char*)__buf + __buf_size, __flags, __x);
381  return __put_integer(__ibeg, (char*)__buf + __buf_size, __s, __f, __flags, __fill);
382}
383
384template <class _CharT, class _OutputIter>
385_OutputIter _STLP_CALL
386__do_put_bool(_OutputIter __s, ios_base& __f, _CharT __fill, bool __x) {
387  const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__f.getloc());
388
389  basic_string<_CharT, char_traits<_CharT>, allocator<_CharT> > __str = __x ? __np.truename() : __np.falsename();
390
391  streamsize __wid = __f.width(0);
392  if (__str.size() >= __STATIC_CAST(size_t, __wid))
393    return _STLP_STD::copy(__str.begin(), __str.end(), __s);
394  else {
395    streamsize __pad = __wid - __str.size();
396    ios_base::fmtflags __dir = __f.flags() & ios_base::adjustfield;
397
398    if (__dir == ios_base::left) {
399      __s = _STLP_STD::copy(__str.begin(), __str.end(), __s);
400      return __fill_n(__s, __pad, __fill);
401    }
402    else /* covers right and internal padding */ {
403      __s = __fill_n(__s, __pad, __fill);
404      return _STLP_STD::copy(__str.begin(), __str.end(), __s);
405    }
406  }
407}
408_STLP_MOVE_TO_STD_NAMESPACE
409
410//
411// num_put<>
412//
413
414template <class _CharT, class _OutputIterator>
415locale::id num_put<_CharT, _OutputIterator>::id;
416
417#if !defined (_STLP_NO_BOOL)
418template <class _CharT, class _OutputIter>
419_OutputIter
420num_put<_CharT, _OutputIter>::do_put(_OutputIter __s, ios_base& __f, _CharT __fill,
421                                     bool __val) const {
422  if (!(__f.flags() & ios_base::boolalpha))
423    // 22.2.2.2.2.23: shall return do_put for int and not directly __do_put_integer.
424    return do_put(__s, __f, __fill, __STATIC_CAST(long, __val));
425
426  return _STLP_PRIV __do_put_bool(__s, __f, __fill, __val);
427}
428#endif
429
430template <class _CharT, class _OutputIter>
431_OutputIter
432num_put<_CharT, _OutputIter>::do_put(_OutputIter __s, ios_base& __f, _CharT __fill,
433                                     long __val) const
434{ return _STLP_PRIV __do_put_integer(__s, __f, __fill, __val); }
435
436template <class _CharT, class _OutputIter>
437_OutputIter
438num_put<_CharT, _OutputIter>::do_put(_OutputIter __s, ios_base& __f, _CharT __fill,
439                                     unsigned long __val) const
440{ return _STLP_PRIV __do_put_integer(__s, __f, __fill, __val); }
441
442template <class _CharT, class _OutputIter>
443_OutputIter
444num_put<_CharT, _OutputIter>::do_put(_OutputIter __s, ios_base& __f, _CharT __fill,
445                                     double __val) const
446{ return _STLP_PRIV __do_put_float(__s, __f, __fill, __val); }
447
448#if !defined (_STLP_NO_LONG_DOUBLE)
449template <class _CharT, class _OutputIter>
450_OutputIter
451num_put<_CharT, _OutputIter>::do_put(_OutputIter __s, ios_base& __f, _CharT __fill,
452                                     long double __val) const
453{ return _STLP_PRIV __do_put_float(__s, __f, __fill, __val); }
454#endif
455
456#if defined (_STLP_LONG_LONG)
457template <class _CharT, class _OutputIter>
458_OutputIter
459num_put<_CharT, _OutputIter>::do_put(_OutputIter __s, ios_base& __f, _CharT __fill,
460                                     _STLP_LONG_LONG __val) const
461{ return _STLP_PRIV __do_put_integer(__s, __f, __fill, __val); }
462
463template <class _CharT, class _OutputIter>
464_OutputIter
465num_put<_CharT, _OutputIter>::do_put(_OutputIter __s, ios_base& __f, _CharT __fill,
466                                     unsigned _STLP_LONG_LONG __val) const
467{ return _STLP_PRIV __do_put_integer(__s, __f, __fill, __val); }
468#endif /* _STLP_LONG_LONG */
469
470
471// 22.2.2.2.2 Stage 1: "For conversion from void* the specifier is %p."
472// This is not clear and I'm really don't follow this (below).
473template <class _CharT, class _OutputIter>
474_OutputIter
475num_put<_CharT, _OutputIter>::do_put(_OutputIter __s, ios_base& __f, _CharT /*__fill*/,
476                                     const void* __val) const {
477  const ctype<_CharT>& __c_type = use_facet<ctype<_CharT> >(__f.getloc());
478  ios_base::fmtflags __save_flags = __f.flags();
479
480  __f.setf(ios_base::hex, ios_base::basefield);
481  __f.setf(ios_base::showbase);
482  __f.setf(ios_base::internal, ios_base::adjustfield);
483  __f.width((sizeof(void*) * 2) + 2); // digits in pointer type plus '0x' prefix
484  if ( __val == 0 ) {
485    // base ('0x') not shown for null, but I really want to type it
486    // for pointer. Print it first in this case.
487    const char* __table_ptr = (__save_flags & ios_base::uppercase) ?
488            _STLP_PRIV __hex_char_table_hi() : _STLP_PRIV __hex_char_table_lo();
489    __s++ = __c_type.widen( '0' );
490    __s++ = __c_type.widen( __table_ptr[16] );
491    __f.width((sizeof(void*) * 2)); // digits in pointer type
492  } else {
493    __f.width((sizeof(void*) * 2) + 2); // digits in pointer type plus '0x' prefix
494  }
495#if defined (_STLP_MSVC)
496#  pragma warning (push)
497#  pragma warning (disable : 4311) //pointer truncation from 'const void*' to 'unsigned long'
498#endif
499  _OutputIter result =
500#ifdef _STLP_LONG_LONG
501    ( sizeof(void*) == sizeof(unsigned long) ) ?
502#endif
503    _STLP_PRIV __do_put_integer(__s, __f, __c_type.widen('0'), __REINTERPRET_CAST(unsigned long,__val))
504#ifdef _STLP_LONG_LONG
505      : /* ( sizeof(void*) == sizeof(unsigned _STLP_LONG_LONG) ) ? */
506    _STLP_PRIV __do_put_integer(__s, __f, __c_type.widen('0'), __REINTERPRET_CAST(unsigned _STLP_LONG_LONG,__val))
507#endif
508        ;
509#if defined (_STLP_MSVC)
510#  pragma warning (pop)
511#endif
512  __f.flags(__save_flags);
513  return result;
514}
515
516_STLP_END_NAMESPACE
517
518#endif /* _STLP_NUM_PUT_C */
519
520// Local Variables:
521// mode:C++
522// End:
523