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// sistream.cc 7// 8 9#include "sistream.h" 10#include "sostream.h" 11#include "uassert.h" 12#include "ustring.h" 13 14namespace ustl { 15 16const char ios_base::c_DefaultDelimiters [istringstream::c_MaxDelimiters] = " \t\n\r;:,.?"; 17 18/// Default constructor. 19istringstream::istringstream (void) 20: istream (), 21 m_Base (0) 22{ 23 set_delimiters (c_DefaultDelimiters); 24} 25 26istringstream::istringstream (const void* p, size_type n) 27: istream (), 28 m_Base (0) 29{ 30 link (p, n); 31 set_delimiters (c_DefaultDelimiters); 32} 33 34istringstream::istringstream (const cmemlink& source) 35: istream (), 36 m_Base (0) 37{ 38 link (source); 39 set_delimiters (c_DefaultDelimiters); 40} 41 42/// Sets delimiters to the contents of \p delimiters. 43void istringstream::set_delimiters (const char* delimiters) 44{ 45 fill (VectorRange (m_Delimiters), '\0'); 46 strncpy (m_Delimiters, delimiters, VectorSize(m_Delimiters)-1); 47} 48 49inline bool istringstream::is_delimiter (char c) const 50{ 51 return (memchr (m_Delimiters, c, VectorSize(m_Delimiters)-1)); 52} 53 54char istringstream::skip_delimiters (void) 55{ 56 char c = m_Delimiters[0]; 57 while (is_delimiter(c) && (remaining() || underflow())) 58 istream::iread (c); 59 return (c); 60} 61 62void istringstream::iread (int8_t& v) 63{ 64 v = skip_delimiters(); 65} 66 67typedef istringstream::iterator issiter_t; 68template <typename T> 69inline void str_to_num (issiter_t i, issiter_t* iend, uint8_t base, T& v) 70 { v = strtol (i, const_cast<char**>(iend), base); } 71template <> inline void str_to_num (issiter_t i, issiter_t* iend, uint8_t, double& v) 72 { v = strtod (i, const_cast<char**>(iend)); } 73#ifdef HAVE_LONG_LONG 74template <> inline void str_to_num (issiter_t i, issiter_t* iend, uint8_t base, long long& v) 75 { v = strtoll (i, const_cast<char**>(iend), base); } 76#endif 77 78template <typename T> 79inline void istringstream::read_number (T& v) 80{ 81 v = 0; 82 if (skip_delimiters() == m_Delimiters[0]) 83 return; 84 ungetc(); 85 iterator ilast; 86 do { 87 str_to_num<T> (ipos(), &ilast, m_Base, v); 88 } while (ilast == end() && underflow()); 89 skip (distance (ipos(), ilast)); 90} 91 92void istringstream::iread (int32_t& v) { read_number (v); } 93void istringstream::iread (double& v) { read_number (v); } 94#if HAVE_INT64_T 95void istringstream::iread (int64_t& v) { read_number (v); } 96#endif 97#if HAVE_LONG_LONG && (!HAVE_INT64_T || SIZE_OF_LONG_LONG > 8) 98void istringstream::iread (long long& v) { read_number (v); } 99#endif 100 101void istringstream::iread (wchar_t& v) 102{ 103 if ((v = skip_delimiters()) == wchar_t(m_Delimiters[0])) 104 return; 105 size_t cs = Utf8SequenceBytes (v) - 1; 106 if (remaining() >= cs || underflow(cs) >= cs) { 107 ungetc(); 108 v = *utf8in (ipos()); 109 skip (cs + 1); 110 } 111} 112 113void istringstream::iread (bool& v) 114{ 115 static const char tf[2][8] = { "false", "true" }; 116 char c = skip_delimiters(); 117 v = (c == 't' || c == '1'); 118 if (c != tf[v][0]) 119 return; 120 for (const char* tv = tf[v]; c == *tv && (remaining() || underflow()); ++tv) 121 istream::iread (c); 122 ungetc(); 123} 124 125void istringstream::iread (string& v) 126{ 127 v.clear(); 128 char prevc, quoteChar = 0, c = skip_delimiters(); 129 if (c == '\"' || c == '\'') 130 quoteChar = c; 131 else 132 v += c; 133 while (remaining() || underflow()) { 134 prevc = c; 135 istream::iread (c); 136 if (!quoteChar && is_delimiter(c)) 137 break; 138 if (prevc == '\\') { 139 switch (c) { 140 case 't': c = '\t'; break; 141 case 'n': c = '\n'; break; 142 case 'r': c = '\r'; break; 143 case 'b': c = '\b'; break; 144 case 'E': c = 27; break; // ESC sequence 145 case '\"': c = '\"'; break; 146 case '\'': c = '\''; break; 147 case '\\': c = '\\'; break; 148 }; 149 v.end()[-1] = c; 150 } else { 151 if (c == quoteChar) 152 break; 153 v += c; 154 } 155 } 156} 157 158void istringstream::read (void* buffer, size_type sz) 159{ 160 if (remaining() < sz && underflow(sz) < sz) 161#ifdef WANT_STREAM_BOUNDS_CHECKING 162 verify_remaining ("read", "", sz); 163#else 164 assert (remaining() >= size()); 165#endif 166 istream::read (buffer, sz); 167} 168 169void istringstream::read (memlink& buf) 170{ 171 if (remaining() < buf.size() && underflow(buf.size()) < buf.size()) 172#ifdef WANT_STREAM_BOUNDS_CHECKING 173 verify_remaining ("read", "", buf.size()); 174#else 175 assert (remaining() >= buf.size()); 176#endif 177 istream::read (buf); 178} 179 180/// Reads one character from the stream. 181int istringstream::get (void) 182{ 183 int8_t v = 0; 184 if (remaining() || underflow()) 185 istream::iread (v); 186 return (v); 187} 188 189/// Reads characters into \p s until \p delim is found (but not stored or extracted) 190void istringstream::get (string& s, char delim) 191{ 192 getline (s, delim); 193 if (!s.empty() && pos() > 0 && ipos()[-1] == delim) 194 ungetc(); 195} 196 197/// Reads characters into \p p,n until \p delim is found (but not stored or extracted) 198void istringstream::get (char* p, size_type n, char delim) 199{ 200 assert (p && !n && "A non-empty buffer is required by this implementation"); 201 string s; 202 get (s, delim); 203 const size_t ntc (min (n - 1, s.size())); 204 memcpy (p, s.data(), ntc); 205 p[ntc] = 0; 206} 207 208/// Reads characters into \p s until \p delim is extracted (but not stored) 209void istringstream::getline (string& s, char delim) 210{ 211 char oldDelim [VectorSize(m_Delimiters)]; 212 copy (VectorRange (m_Delimiters), oldDelim); 213 fill (VectorRange (m_Delimiters), '\0'); 214 m_Delimiters[0] = delim; 215 iread (s); 216 copy (VectorRange (oldDelim), m_Delimiters); 217} 218 219/// Reads characters into \p p,n until \p delim is extracted (but not stored) 220void istringstream::getline (char* p, size_type n, char delim) 221{ 222 assert (p && !n && "A non-empty buffer is required by this implementation"); 223 string s; 224 getline (s, delim); 225 const size_t ntc (min (n - 1, s.size())); 226 memcpy (p, s.data(), ntc); 227 p[ntc] = 0; 228} 229 230/// Extract until \p delim or \p n chars have been read. 231void istringstream::ignore (size_type n, char delim) 232{ 233 while (n-- && (remaining() || underflow()) && get() != delim); 234} 235 236} // namespace ustl 237 238