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_OSTREAM_C
19#define _STLP_OSTREAM_C
20
21#ifndef _STLP_INTERNAL_OSTREAM_H
22#  include <stl/_ostream.h>
23#endif
24
25#if !defined (_STLP_INTERNAL_NUM_PUT_H)
26#  include <stl/_num_put.h>            // For basic_streambuf and iterators
27#endif
28
29_STLP_BEGIN_NAMESPACE
30
31//----------------------------------------------------------------------
32// Definitions of non-inline member functions.
33
34// Constructor, destructor
35
36template <class _CharT, class _Traits>
37basic_ostream<_CharT, _Traits>::basic_ostream(basic_streambuf<_CharT, _Traits>* __buf)
38    : basic_ios<_CharT, _Traits>() {
39  this->init(__buf);
40}
41
42template <class _CharT, class _Traits>
43basic_ostream<_CharT, _Traits>::~basic_ostream()
44{}
45
46// Output directly from a streambuf.
47template <class _CharT, class _Traits>
48basic_ostream<_CharT, _Traits>&
49basic_ostream<_CharT, _Traits>::operator<<(basic_streambuf<_CharT, _Traits>* __from) {
50  sentry __sentry(*this);
51  if (__sentry) {
52    if (__from) {
53      bool __any_inserted = __from->gptr() != __from->egptr()
54        ? this->_M_copy_buffered(__from, this->rdbuf())
55        : this->_M_copy_unbuffered(__from, this->rdbuf());
56      if (!__any_inserted)
57        this->setstate(ios_base::failbit);
58    }
59    else
60      this->setstate(ios_base::badbit);
61  }
62
63  return *this;
64}
65
66// Helper functions for the streambuf version of operator<<.  The
67// exception-handling code is complicated because exceptions thrown
68// while extracting characters are treated differently than exceptions
69// thrown while inserting characters.
70
71template <class _CharT, class _Traits>
72bool basic_ostream<_CharT, _Traits>
73  ::_M_copy_buffered(basic_streambuf<_CharT, _Traits>* __from,
74                     basic_streambuf<_CharT, _Traits>* __to) {
75  bool __any_inserted = false;
76
77  while (__from->egptr() != __from->gptr()) {
78    const ptrdiff_t __avail = __from->egptr() - __from->gptr();
79
80    streamsize __nwritten;
81    _STLP_TRY {
82      __nwritten = __to->sputn(__from->gptr(), __avail);
83      __from->gbump((int)__nwritten);
84    }
85    _STLP_CATCH_ALL {
86      this->_M_handle_exception(ios_base::badbit);
87      return __any_inserted;
88    }
89
90    if (__nwritten == __avail) {
91      _STLP_TRY {
92        if (this->_S_eof(__from->sgetc()))
93          return true;
94        else
95          __any_inserted = true;
96      }
97      _STLP_CATCH_ALL {
98        this->_M_handle_exception(ios_base::failbit);
99        return false;
100      }
101    }
102    else if (__nwritten != 0)
103      return true;
104    else
105      return __any_inserted;
106  }
107
108  // No characters are in the buffer, but we aren't at EOF.  Switch to
109  // unbuffered mode.
110  return __any_inserted || this->_M_copy_unbuffered(__from, __to);
111}
112
113/*
114 * Helper struct (guard) to put back a character in a streambuf
115 * whenever an exception or an eof occur.
116 */
117template <class _CharT, class _Traits>
118struct _SPutBackC {
119  typedef basic_streambuf<_CharT, _Traits> _StreamBuf;
120  typedef typename _StreamBuf::int_type int_type;
121  _SPutBackC(_StreamBuf *pfrom)
122    : __pfrom(pfrom), __c(0), __do_guard(false) {}
123  ~_SPutBackC() {
124    if (__do_guard) {
125      __pfrom->sputbackc(_Traits::to_char_type(__c));
126    }
127  }
128
129  void guard(int_type c) {
130    __c = c;
131    __do_guard = true;
132  }
133  void release() {
134    __do_guard = false;
135  }
136
137private:
138  _StreamBuf *__pfrom;
139  int_type __c;
140  bool __do_guard;
141};
142
143template <class _CharT, class _Traits>
144bool basic_ostream<_CharT, _Traits>
145  ::_M_copy_unbuffered(basic_streambuf<_CharT, _Traits>* __from,
146                       basic_streambuf<_CharT, _Traits>* __to) {
147  typedef _SPutBackC<_CharT, _Traits> _SPutBackCGuard;
148  bool __any_inserted = false;
149  int_type __c;
150
151  _STLP_TRY {
152    _SPutBackCGuard __cguard(__from);
153    for (;;) {
154      _STLP_TRY {
155        __c = __from->sbumpc();
156      }
157      _STLP_CATCH_ALL {
158        this->_M_handle_exception(ios_base::failbit);
159        break;
160      }
161
162      if (this->_S_eof(__c))
163        break;
164
165      __cguard.guard(__c);
166#if defined (__DMC__)
167      _STLP_TRY {
168#endif
169      if (this->_S_eof(__to->sputc(_Traits::to_char_type(__c))))
170        break;
171
172#if defined (__DMC__)
173      }
174      _STLP_CATCH_ALL {
175        this->_M_handle_exception(ios_base::badbit);
176        break;
177      }
178#endif
179      __cguard.release();
180      __any_inserted = true;
181    }
182  }
183  _STLP_CATCH_ALL {
184    this->_M_handle_exception(ios_base::badbit);
185  }
186  return __any_inserted;
187}
188
189_STLP_MOVE_TO_PRIV_NAMESPACE
190
191// Helper function for numeric output.
192template <class _CharT, class _Traits, class _Number>
193basic_ostream<_CharT, _Traits>&  _STLP_CALL
194__put_num(basic_ostream<_CharT, _Traits>& __os, _Number __x) {
195  typedef typename basic_ostream<_CharT, _Traits>::sentry _Sentry;
196  _Sentry __sentry(__os);
197  bool __failed = true;
198
199  if (__sentry) {
200    _STLP_TRY {
201      typedef num_put<_CharT, ostreambuf_iterator<_CharT, _Traits> > _NumPut;
202      __failed = (use_facet<_NumPut>(__os.getloc())).put(ostreambuf_iterator<_CharT, _Traits>(__os.rdbuf()),
203                                                         __os, __os.fill(),
204                                                         __x).failed();
205    }
206    _STLP_CATCH_ALL {
207      __os._M_handle_exception(ios_base::badbit);
208    }
209  }
210  if (__failed)
211    __os.setstate(ios_base::badbit);
212  return __os;
213}
214
215_STLP_MOVE_TO_STD_NAMESPACE
216
217/*
218 * In the following operators we try to limit code bloat by limiting the
219 * number of __put_num instanciations.
220 */
221template <class _CharT, class _Traits>
222basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(short __x) {
223  _STLP_STATIC_ASSERT( sizeof(short) <= sizeof(long) )
224  long __tmp = ((this->flags() & _Basic_ios::basefield) != ios_base::dec) ?
225                  __STATIC_CAST(long, __STATIC_CAST(unsigned short, __x)): __x;
226  return _STLP_PRIV __put_num(*this, __tmp);
227}
228
229template <class _CharT, class _Traits>
230basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(unsigned short __x) {
231  _STLP_STATIC_ASSERT( sizeof(unsigned short) <= sizeof(unsigned long) )
232  return _STLP_PRIV __put_num(*this, __STATIC_CAST(unsigned long,__x));
233}
234
235template <class _CharT, class _Traits>
236basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(int __x) {
237  _STLP_STATIC_ASSERT( sizeof(int) <= sizeof(long) )
238  long __tmp = ((this->flags() & _Basic_ios::basefield) != ios_base::dec) ?
239                  __STATIC_CAST(long, __STATIC_CAST(unsigned int, __x)): __x;
240  return _STLP_PRIV __put_num(*this, __tmp);
241}
242
243template <class _CharT, class _Traits>
244#if defined (_WIN64) || !defined (_STLP_MSVC) || (_STLP_MSVC < 1300)
245basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(unsigned int __x) {
246  _STLP_STATIC_ASSERT( sizeof(unsigned int) <= sizeof(unsigned long) )
247#else
248/* We define this operator with size_t rather than unsigned int to avoid
249 * 64 bits warning.
250 */
251basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(size_t __x) {
252  _STLP_STATIC_ASSERT( sizeof(size_t) <= sizeof(unsigned long) )
253#endif
254  return _STLP_PRIV __put_num(*this,  __STATIC_CAST(unsigned long,__x));
255}
256
257template <class _CharT, class _Traits>
258basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(long __x)
259{ return _STLP_PRIV __put_num(*this,  __x); }
260
261template <class _CharT, class _Traits>
262basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(unsigned long __x)
263{ return _STLP_PRIV __put_num(*this,  __x); }
264
265#ifdef _STLP_LONG_LONG
266template <class _CharT, class _Traits>
267basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<< (_STLP_LONG_LONG __x)
268{ return _STLP_PRIV __put_num(*this,  __x); }
269
270template <class _CharT, class _Traits>
271basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<< (unsigned _STLP_LONG_LONG __x)
272{ return _STLP_PRIV __put_num(*this,  __x); }
273#endif
274
275template <class _CharT, class _Traits>
276basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(float __x)
277{ return _STLP_PRIV __put_num(*this,  __STATIC_CAST(double,__x)); }
278
279template <class _CharT, class _Traits>
280basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(double __x)
281{ return _STLP_PRIV __put_num(*this,  __x); }
282
283#ifndef _STLP_NO_LONG_DOUBLE
284template <class _CharT, class _Traits>
285basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(long double __x)
286{ return _STLP_PRIV __put_num(*this,  __x); }
287#endif
288
289template <class _CharT, class _Traits>
290basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(const void* __x)
291{ return _STLP_PRIV __put_num(*this,  __x); }
292
293#ifndef _STLP_NO_BOOL
294template <class _CharT, class _Traits>
295basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>::operator<<(bool __x)
296{ return _STLP_PRIV __put_num(*this,  __x); }
297#endif
298
299template <class _CharT, class _Traits>
300void basic_ostream<_CharT, _Traits>::_M_put_char(_CharT __c) {
301  sentry __sentry(*this);
302  if (__sentry) {
303    bool __failed = true;
304    _STLP_TRY {
305      streamsize __npad = this->width() > 0 ? this->width() - 1 : 0;
306      //      if (__npad <= 1)
307      if (__npad == 0)
308        __failed = this->_S_eof(this->rdbuf()->sputc(__c));
309      else if ((this->flags() & ios_base::adjustfield) == ios_base::left) {
310        __failed = this->_S_eof(this->rdbuf()->sputc(__c));
311        __failed = __failed ||
312                   this->rdbuf()->_M_sputnc(this->fill(), __npad) != __npad;
313      }
314      else {
315        __failed = this->rdbuf()->_M_sputnc(this->fill(), __npad) != __npad;
316        __failed = __failed || this->_S_eof(this->rdbuf()->sputc(__c));
317      }
318
319      this->width(0);
320    }
321    _STLP_CATCH_ALL {
322      this->_M_handle_exception(ios_base::badbit);
323    }
324
325    if (__failed)
326      this->setstate(ios_base::badbit);
327  }
328}
329
330template <class _CharT, class _Traits>
331void basic_ostream<_CharT, _Traits>::_M_put_nowiden(const _CharT* __s) {
332  sentry __sentry(*this);
333  if (__sentry) {
334    bool __failed = true;
335    streamsize __n = _Traits::length(__s);
336    streamsize __npad = this->width() > __n ? this->width() - __n : 0;
337
338    _STLP_TRY {
339      if (__npad == 0)
340        __failed = this->rdbuf()->sputn(__s, __n) != __n;
341      else if ((this->flags() & ios_base::adjustfield) == ios_base::left) {
342        __failed = this->rdbuf()->sputn(__s, __n) != __n;
343        __failed = __failed ||
344                   this->rdbuf()->_M_sputnc(this->fill(), __npad) != __npad;
345      }
346      else {
347        __failed = this->rdbuf()->_M_sputnc(this->fill(), __npad) != __npad;
348        __failed = __failed || this->rdbuf()->sputn(__s, __n) != __n;
349      }
350
351      this->width(0);
352    }
353    _STLP_CATCH_ALL {
354      this->_M_handle_exception(ios_base::badbit);
355    }
356
357    if (__failed)
358      this->setstate(ios_base::failbit);
359  }
360}
361
362template <class _CharT, class _Traits>
363void basic_ostream<_CharT, _Traits>::_M_put_widen(const char* __s) {
364  sentry __sentry(*this);
365  if (__sentry) {
366    bool __failed = true;
367    streamsize __n = char_traits<char>::length(__s);
368    streamsize __npad = this->width() > __n ? this->width() - __n : 0;
369
370    _STLP_TRY {
371      if (__npad == 0)
372        __failed = !this->_M_put_widen_aux(__s, __n);
373      else if ((this->flags() & ios_base::adjustfield) == ios_base::left) {
374        __failed = !this->_M_put_widen_aux(__s, __n);
375        __failed = __failed ||
376                   this->rdbuf()->_M_sputnc(this->fill(), __npad) != __npad;
377      }
378      else {
379        __failed = this->rdbuf()->_M_sputnc(this->fill(), __npad) != __npad;
380        __failed = __failed || !this->_M_put_widen_aux(__s, __n);
381      }
382
383      this->width(0);
384    }
385    _STLP_CATCH_ALL {
386      this->_M_handle_exception(ios_base::badbit);
387    }
388
389    if (__failed)
390      this->setstate(ios_base::failbit);
391  }
392}
393
394template <class _CharT, class _Traits>
395bool basic_ostream<_CharT, _Traits>::_M_put_widen_aux(const char* __s,
396                                                      streamsize __n) {
397  basic_streambuf<_CharT, _Traits>* __buf = this->rdbuf();
398
399  for ( ; __n > 0 ; --__n)
400    if (this->_S_eof(__buf->sputc(this->widen(*__s++))))
401      return false;
402  return true;
403}
404
405// Unformatted output of a single character.
406template <class _CharT, class _Traits>
407basic_ostream<_CharT, _Traits>&
408basic_ostream<_CharT, _Traits>::put(char_type __c) {
409  sentry __sentry(*this);
410  bool __failed = true;
411
412  if (__sentry) {
413    _STLP_TRY {
414      __failed = this->_S_eof(this->rdbuf()->sputc(__c));
415    }
416    _STLP_CATCH_ALL {
417      this->_M_handle_exception(ios_base::badbit);
418    }
419  }
420
421  if (__failed)
422    this->setstate(ios_base::badbit);
423
424  return *this;
425}
426
427// Unformatted output of a single character.
428template <class _CharT, class _Traits>
429basic_ostream<_CharT, _Traits>&
430basic_ostream<_CharT, _Traits>::write(const char_type* __s, streamsize __n) {
431  sentry __sentry(*this);
432  bool __failed = true;
433
434  if (__sentry) {
435    _STLP_TRY {
436      __failed = this->rdbuf()->sputn(__s, __n) != __n;
437    }
438    _STLP_CATCH_ALL {
439      this->_M_handle_exception(ios_base::badbit);
440    }
441  }
442
443  if (__failed)
444    this->setstate(ios_base::badbit);
445
446  return *this;
447}
448
449_STLP_END_NAMESPACE
450
451#endif /* _STLP_OSTREAM_C */
452
453// Local Variables:
454// mode:C++
455// End:
456