| // This file is part of the ustl library, an STL implementation. |
| // |
| // Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> |
| // This file is free software, distributed under the MIT License. |
| // |
| // sostream.h |
| // |
| |
| #include "mistream.h" // for istream_iterator, referenced in utf8.h |
| #include "sostream.h" |
| #include "uassert.h" |
| #include "ulimits.h" |
| #include "ustring.h" |
| #include <stdio.h> |
| |
| namespace ustl { |
| |
| /// Creates an output string stream linked to the given memory area. |
| ostringstream::ostringstream (void* p, size_t n) |
| : ostream (), |
| m_Buffer (), |
| m_Flags (0), |
| m_Width (0), |
| m_Base (10), |
| m_Precision (2) |
| { |
| link (p, n); |
| } |
| |
| /// Creates an output string stream, initializing the buffer with v. |
| ostringstream::ostringstream (const string& v) |
| : ostream (), |
| m_Buffer (v), |
| m_Flags (0), |
| m_Width (0), |
| m_Base (10), |
| m_Precision (2) |
| { |
| ostream::link (m_Buffer); |
| } |
| |
| /// Copies \p s to the internal buffer. |
| void ostringstream::str (const string& s) |
| { |
| m_Buffer = s; |
| ostream::link (m_Buffer); |
| SetPos (m_Buffer.size()); |
| } |
| |
| /// Writes a single character into the stream. |
| void ostringstream::iwrite (uint8_t v) |
| { |
| if (remaining() >= 1 || overflow() >= 1) |
| ostream::iwrite (v); |
| } |
| |
| /// Writes \p buf of size \p bufSize through the internal buffer. |
| void ostringstream::write_buffer (const char* buf, size_type bufSize) |
| { |
| size_type btw = 0, written = 0; |
| while ((written += btw) < bufSize && (remaining() || overflow(bufSize - written))) |
| write (buf + written, btw = min (remaining(), bufSize - written)); |
| } |
| |
| /// Simple decimal encoding of \p n into \p fmt. |
| inline char* ostringstream::encode_dec (char* fmt, uint32_t n) const |
| { |
| do { |
| *fmt++ = '0' + n % 10; |
| } while (n /= 10); |
| return (fmt); |
| } |
| |
| /// Generates a sprintf format string for the given type. |
| void ostringstream::fmtstring (char* fmt, const char* typestr, bool bInteger) const |
| { |
| *fmt++ = '%'; |
| if (m_Width) |
| fmt = encode_dec (fmt, m_Width); |
| if (m_Flags & left) |
| *fmt++ = '-'; |
| if (!bInteger) { |
| *fmt++ = '.'; |
| fmt = encode_dec (fmt, m_Precision); |
| } |
| while (*typestr) |
| *fmt++ = *typestr++; |
| if (bInteger) { |
| if (m_Base == 16) |
| fmt[-1] = 'X'; |
| else if (m_Base == 8) |
| fmt[-1] = 'o'; |
| } else { |
| if (m_Flags & scientific) |
| fmt[-1] = 'E'; |
| } |
| *fmt = 0; |
| } |
| |
| /// Writes \p v into the stream as utf8 |
| void ostringstream::iwrite (wchar_t v) |
| { |
| char buffer [8]; |
| *utf8out(buffer) = v; |
| write_buffer (buffer, Utf8Bytes(v)); |
| } |
| |
| /// Writes value \p v into the stream as text. |
| void ostringstream::iwrite (bool v) |
| { |
| static const char tf[2][8] = { "false", "true" }; |
| write_buffer (tf[v], 5 - v); |
| } |
| |
| /// Equivalent to a vsprintf on the string. |
| int ostringstream::vformat (const char* fmt, va_list args) |
| { |
| #if HAVE_VA_COPY |
| va_list args2; |
| #else |
| #define args2 args |
| #undef __va_copy |
| #define __va_copy(x,y) |
| #endif |
| size_t rv, space; |
| do { |
| space = remaining(); |
| __va_copy (args2, args); |
| rv = vsnprintf (ipos(), space, fmt, args2); |
| if (ssize_t(rv) < 0) |
| rv = space; |
| } while (rv >= space && rv < overflow(rv + 1)); |
| SetPos (pos() + min (rv, space)); |
| return (rv); |
| } |
| |
| /// Equivalent to a sprintf on the string. |
| int ostringstream::format (const char* fmt, ...) |
| { |
| va_list args; |
| va_start (args, fmt); |
| const int rv = vformat (fmt, args); |
| va_end (args); |
| return (rv); |
| } |
| |
| /// Links to string \p l as resizable. |
| void ostringstream::link (void* p, size_t n) |
| { |
| assert ((p || !n) && "The output string buffer must not be read-only"); |
| ostream::link (p, n); |
| m_Buffer.link (p, n); |
| } |
| |
| /// Writes the contents of \p buffer of \p size into the stream. |
| void ostringstream::write (const void* buffer, size_type sz) |
| { |
| if (remaining() < sz && overflow(sz) < sz) |
| return; |
| ostream::write (buffer, sz); |
| } |
| |
| /// Writes the contents of \p buf into the stream. |
| void ostringstream::write (const cmemlink& buf) |
| { |
| if (remaining() < buf.size() && overflow(buf.size()) < buf.size()) |
| return; |
| ostream::write (buf); |
| } |
| |
| /// Flushes the internal buffer by truncating it at the current position. |
| void ostringstream::flush (void) |
| { |
| m_Buffer.resize (pos()); |
| } |
| |
| /// Attempts to create more output space. Returns remaining(). |
| ostringstream::size_type ostringstream::overflow (size_type n) |
| { |
| if (n > remaining()) { |
| const uoff_t oldPos (pos()); |
| m_Buffer.reserve (oldPos + n, false); |
| m_Buffer.resize (oldPos + n); |
| ostream::link (m_Buffer); |
| SetPos (oldPos); |
| } |
| verify_remaining ("write", "text", n); |
| return (remaining()); |
| } |
| |
| } // namespace ustl |
| |
| |