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