1// This file is part of the ustl library, an STL implementation.
2//
3// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
4// This file is free software, distributed under the MIT License.
5//
6// sostream.h
7//
8
9#include "mistream.h"	// for istream_iterator, referenced in utf8.h
10#include "sostream.h"
11#include "uassert.h"
12#include "ulimits.h"
13#include "ustring.h"
14#include <stdio.h>
15
16namespace ustl {
17
18/// Creates an output string stream linked to the given memory area.
19ostringstream::ostringstream (void* p, size_t n)
20: ostream (),
21  m_Buffer (),
22  m_Flags (0),
23  m_Width (0),
24  m_Base (10),
25  m_Precision (2)
26{
27    link (p, n);
28}
29
30/// Creates an output string stream, initializing the buffer with v.
31ostringstream::ostringstream (const string& v)
32: ostream (),
33  m_Buffer (v),
34  m_Flags (0),
35  m_Width (0),
36  m_Base (10),
37  m_Precision (2)
38{
39    ostream::link (m_Buffer);
40}
41
42/// Copies \p s to the internal buffer.
43void ostringstream::str (const string& s)
44{
45    m_Buffer = s;
46    ostream::link (m_Buffer);
47    SetPos (m_Buffer.size());
48}
49
50/// Writes a single character into the stream.
51void ostringstream::iwrite (uint8_t v)
52{
53    if (remaining() >= 1 || overflow() >= 1)
54	ostream::iwrite (v);
55}
56
57/// Writes \p buf of size \p bufSize through the internal buffer.
58void ostringstream::write_buffer (const char* buf, size_type bufSize)
59{
60    size_type btw = 0, written = 0;
61    while ((written += btw) < bufSize && (remaining() || overflow(bufSize - written)))
62	write (buf + written, btw = min (remaining(), bufSize - written));
63}
64
65/// Simple decimal encoding of \p n into \p fmt.
66inline char* ostringstream::encode_dec (char* fmt, uint32_t n) const
67{
68    do {
69	*fmt++ = '0' + n % 10;
70    } while (n /= 10);
71    return (fmt);
72}
73
74/// Generates a sprintf format string for the given type.
75void ostringstream::fmtstring (char* fmt, const char* typestr, bool bInteger) const
76{
77    *fmt++ = '%';
78    if (m_Width)
79	fmt = encode_dec (fmt, m_Width);
80    if (m_Flags & left)
81	*fmt++ = '-';
82    if (!bInteger) {
83	*fmt++ = '.';
84	fmt = encode_dec (fmt, m_Precision);
85    }
86    while (*typestr)
87	*fmt++ = *typestr++;
88    if (bInteger) {
89	if (m_Base == 16)
90	    fmt[-1] = 'X';
91	else if (m_Base == 8)
92	    fmt[-1] = 'o';
93    } else {
94	if (m_Flags & scientific)
95	    fmt[-1] = 'E';
96    }
97    *fmt = 0;
98}
99
100/// Writes \p v into the stream as utf8
101void ostringstream::iwrite (wchar_t v)
102{
103    char buffer [8];
104    *utf8out(buffer) = v;
105    write_buffer (buffer, Utf8Bytes(v));
106}
107
108/// Writes value \p v into the stream as text.
109void ostringstream::iwrite (bool v)
110{
111    static const char tf[2][8] = { "false", "true" };
112    write_buffer (tf[v], 5 - v);
113}
114
115/// Equivalent to a vsprintf on the string.
116int ostringstream::vformat (const char* fmt, va_list args)
117{
118#if HAVE_VA_COPY
119    va_list args2;
120#else
121    #define args2 args
122    #undef __va_copy
123    #define __va_copy(x,y)
124#endif
125    size_t rv, space;
126    do {
127	space = remaining();
128	__va_copy (args2, args);
129	rv = vsnprintf (ipos(), space, fmt, args2);
130	if (ssize_t(rv) < 0)
131	    rv = space;
132    } while (rv >= space && rv < overflow(rv + 1));
133    SetPos (pos() + min (rv, space));
134    return (rv);
135}
136
137/// Equivalent to a sprintf on the string.
138int ostringstream::format (const char* fmt, ...)
139{
140    va_list args;
141    va_start (args, fmt);
142    const int rv = vformat (fmt, args);
143    va_end (args);
144    return (rv);
145}
146
147/// Links to string \p l as resizable.
148void ostringstream::link (void* p, size_t n)
149{
150    assert ((p || !n) && "The output string buffer must not be read-only");
151    ostream::link (p, n);
152    m_Buffer.link (p, n);
153}
154
155/// Writes the contents of \p buffer of \p size into the stream.
156void ostringstream::write (const void* buffer, size_type sz)
157{
158    if (remaining() < sz && overflow(sz) < sz)
159	return;
160    ostream::write (buffer, sz);
161}
162
163/// Writes the contents of \p buf into the stream.
164void ostringstream::write (const cmemlink& buf)
165{
166    if (remaining() < buf.size() && overflow(buf.size()) < buf.size())
167	return;
168    ostream::write (buf);
169}
170
171/// Flushes the internal buffer by truncating it at the current position.
172void ostringstream::flush (void)
173{
174    m_Buffer.resize (pos());
175}
176
177/// Attempts to create more output space. Returns remaining().
178ostringstream::size_type ostringstream::overflow (size_type n)
179{
180    if (n > remaining()) {
181	const uoff_t oldPos (pos());
182	m_Buffer.reserve (oldPos + n, false);
183	m_Buffer.resize (oldPos + n);
184	ostream::link (m_Buffer);
185	SetPos (oldPos);
186    }
187    verify_remaining ("write", "text", n);
188    return (remaining());
189}
190
191} // namespace ustl
192
193
194