// 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. // // sistream.cc // #include "sistream.h" #include "sostream.h" #include "uassert.h" #include "ustring.h" namespace ustl { const char ios_base::c_DefaultDelimiters [istringstream::c_MaxDelimiters] = " \t\n\r;:,.?"; /// Default constructor. istringstream::istringstream (void) : istream (), m_Base (0) { set_delimiters (c_DefaultDelimiters); } istringstream::istringstream (const void* p, size_type n) : istream (), m_Base (0) { link (p, n); set_delimiters (c_DefaultDelimiters); } istringstream::istringstream (const cmemlink& source) : istream (), m_Base (0) { link (source); set_delimiters (c_DefaultDelimiters); } /// Sets delimiters to the contents of \p delimiters. void istringstream::set_delimiters (const char* delimiters) { fill (VectorRange (m_Delimiters), '\0'); strncpy (m_Delimiters, delimiters, VectorSize(m_Delimiters)-1); } inline bool istringstream::is_delimiter (char c) const { return (memchr (m_Delimiters, c, VectorSize(m_Delimiters)-1)); } char istringstream::skip_delimiters (void) { char c = m_Delimiters[0]; while (is_delimiter(c) && (remaining() || underflow())) istream::iread (c); return (c); } void istringstream::iread (int8_t& v) { v = skip_delimiters(); } typedef istringstream::iterator issiter_t; template <typename T> inline void str_to_num (issiter_t i, issiter_t* iend, uint8_t base, T& v) { v = strtol (i, const_cast<char**>(iend), base); } template <> inline void str_to_num (issiter_t i, issiter_t* iend, uint8_t, double& v) { v = strtod (i, const_cast<char**>(iend)); } #ifdef HAVE_LONG_LONG template <> inline void str_to_num (issiter_t i, issiter_t* iend, uint8_t base, long long& v) { v = strtoll (i, const_cast<char**>(iend), base); } #endif template <typename T> inline void istringstream::read_number (T& v) { v = 0; if (skip_delimiters() == m_Delimiters[0]) return; ungetc(); iterator ilast; do { str_to_num<T> (ipos(), &ilast, m_Base, v); } while (ilast == end() && underflow()); skip (distance (ipos(), ilast)); } void istringstream::iread (int32_t& v) { read_number (v); } void istringstream::iread (double& v) { read_number (v); } #if HAVE_INT64_T void istringstream::iread (int64_t& v) { read_number (v); } #endif #if HAVE_LONG_LONG && (!HAVE_INT64_T || SIZE_OF_LONG_LONG > 8) void istringstream::iread (long long& v) { read_number (v); } #endif void istringstream::iread (wchar_t& v) { if ((v = skip_delimiters()) == wchar_t(m_Delimiters[0])) return; size_t cs = Utf8SequenceBytes (v) - 1; if (remaining() >= cs || underflow(cs) >= cs) { ungetc(); v = *utf8in (ipos()); skip (cs + 1); } } void istringstream::iread (bool& v) { static const char tf[2][8] = { "false", "true" }; char c = skip_delimiters(); v = (c == 't' || c == '1'); if (c != tf[v][0]) return; for (const char* tv = tf[v]; c == *tv && (remaining() || underflow()); ++tv) istream::iread (c); ungetc(); } void istringstream::iread (string& v) { v.clear(); char prevc, quoteChar = 0, c = skip_delimiters(); if (c == '\"' || c == '\'') quoteChar = c; else v += c; while (remaining() || underflow()) { prevc = c; istream::iread (c); if (!quoteChar && is_delimiter(c)) break; if (prevc == '\\') { switch (c) { case 't': c = '\t'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 'b': c = '\b'; break; case 'E': c = 27; break; // ESC sequence case '\"': c = '\"'; break; case '\'': c = '\''; break; case '\\': c = '\\'; break; }; v.end()[-1] = c; } else { if (c == quoteChar) break; v += c; } } } void istringstream::read (void* buffer, size_type sz) { if (remaining() < sz && underflow(sz) < sz) #ifdef WANT_STREAM_BOUNDS_CHECKING verify_remaining ("read", "", sz); #else assert (remaining() >= size()); #endif istream::read (buffer, sz); } void istringstream::read (memlink& buf) { if (remaining() < buf.size() && underflow(buf.size()) < buf.size()) #ifdef WANT_STREAM_BOUNDS_CHECKING verify_remaining ("read", "", buf.size()); #else assert (remaining() >= buf.size()); #endif istream::read (buf); } /// Reads one character from the stream. int istringstream::get (void) { int8_t v = 0; if (remaining() || underflow()) istream::iread (v); return (v); } /// Reads characters into \p s until \p delim is found (but not stored or extracted) void istringstream::get (string& s, char delim) { getline (s, delim); if (!s.empty() && pos() > 0 && ipos()[-1] == delim) ungetc(); } /// Reads characters into \p p,n until \p delim is found (but not stored or extracted) void istringstream::get (char* p, size_type n, char delim) { assert (p && !n && "A non-empty buffer is required by this implementation"); string s; get (s, delim); const size_t ntc (min (n - 1, s.size())); memcpy (p, s.data(), ntc); p[ntc] = 0; } /// Reads characters into \p s until \p delim is extracted (but not stored) void istringstream::getline (string& s, char delim) { char oldDelim [VectorSize(m_Delimiters)]; copy (VectorRange (m_Delimiters), oldDelim); fill (VectorRange (m_Delimiters), '\0'); m_Delimiters[0] = delim; iread (s); copy (VectorRange (oldDelim), m_Delimiters); } /// Reads characters into \p p,n until \p delim is extracted (but not stored) void istringstream::getline (char* p, size_type n, char delim) { assert (p && !n && "A non-empty buffer is required by this implementation"); string s; getline (s, delim); const size_t ntc (min (n - 1, s.size())); memcpy (p, s.data(), ntc); p[ntc] = 0; } /// Extract until \p delim or \p n chars have been read. void istringstream::ignore (size_type n, char delim) { while (n-- && (remaining() || underflow()) && get() != delim); } } // namespace ustl