1/* Copyright (c) 2012 Massachusetts Institute of Technology 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to deal 5 * in the Software without restriction, including without limitation the rights 6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 * copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 * THE SOFTWARE. 20 */ 21 22#include "String.h" 23 24#include <cstdarg> 25#include <cstdio> 26#include <iostream> 27#include <ios> 28 29namespace LibUtil 30{ 31 const unsigned int String::msBufferSize = 4096; 32 33 String String::format(const String& format_, ...) 34 { 35 char buffer[msBufferSize]; 36 37 va_list args; 38 va_start(args, format_); 39 vsnprintf(buffer, msBufferSize, format_.c_str(), args); 40 va_end(args); 41 42 return (String)(buffer); 43 } 44 45 String String::format(const String& format_, va_list args_) 46 { 47 char buffer[msBufferSize]; 48 49 vsnprintf(buffer, msBufferSize, format_.c_str(), args_); 50 51 return (String)(buffer); 52 } 53 54 String::String() 55 {} 56 57 String::String(const string& str_) 58 : string(str_) 59 {} 60 61 String::String(const char* str_, size_t n_) 62 : string(str_, n_) 63 {} 64 65 String::String(const char* str_) 66 : string(str_) 67 {} 68 69 String::String(size_t n_, char c_) 70 : string(n_, c_) 71 {} 72 73 String::String(int value_) 74 : string(toString<int>(value_)) 75 {} 76 77 String::String(unsigned int value_) 78 : string(toString<unsigned int>(value_)) 79 {} 80 81 String::String(long value_) 82 : string(toString<long>(value_)) 83 {} 84 85 String::String(unsigned long value_) 86 : string(toString<unsigned long>(value_)) 87 {} 88 89 String::String(float value_) 90 : string(toString<float>(value_)) 91 {} 92 93 String::String(double value_) 94 : string(toString<double>(value_)) 95 {} 96 97 String::String(bool value_) 98 : string(toString<bool>(value_)) 99 {} 100 101 String::~String() 102 {} 103 104 String& String::trim() 105 { 106 // Remove leading and trailing whitespace 107 static const char whitespace[] = " \n\t\v\r\f"; 108 erase(0, find_first_not_of(whitespace)); 109 erase(find_last_not_of(whitespace) + 1U); 110 return (*this); 111 } 112 113 String& String::substitute(const String& str1_, const String& str2_) 114 { 115 size_t str1Size = str1_.size(); 116 size_t str2Size = str2_.size(); 117 118 size_t pos; 119 pos = find(str1_); 120 while(pos != string::npos) 121 { 122 replace(pos, str1Size, str2_); 123 pos += str2Size; 124 pos = find(str1_, pos); 125 } 126 return (*this); 127 } 128 129 vector<String> String::split(const char* delimiters_) const 130 { 131 vector<String> result; 132 133 if(size() == 0) 134 { 135 return result; 136 } 137 138 size_t currPos, nextPos; 139 currPos = 0; 140 nextPos = find_first_of(delimiters_); 141 while(1) 142 { 143 if(nextPos == string::npos) 144 { 145 if(currPos != size()) 146 { 147 result.push_back(substr(currPos)); 148 } 149 break; 150 } 151 152 if(nextPos != currPos) 153 { 154 result.push_back(substr(currPos, nextPos - currPos)); 155 } 156 currPos = nextPos + 1; 157 nextPos = find_first_of(delimiters_, currPos); 158 } 159 160 return result; 161 } 162 163 vector<String> String::split(const String* delimiters_, unsigned int num_delimiters_) const 164 { 165 vector<String> result; 166 167 if(size() == 0) 168 { 169 return result; 170 } 171 172 if(num_delimiters_ == 1) 173 { 174 size_t currPos, nextPos; 175 currPos = 0; 176 nextPos = find(delimiters_[0]); 177 while(1) 178 { 179 if(nextPos == String::npos) 180 { 181 result.push_back(substr(currPos)); 182 break; 183 } 184 185 if(nextPos != currPos) 186 { 187 result.push_back(substr(currPos, nextPos - currPos)); 188 } 189 currPos = nextPos + delimiters_[0].size(); 190 nextPos = find(delimiters_[0], currPos); 191 } 192 } 193 else 194 { 195 // Currently the length of the delimiters are not checked 196 unsigned int delimiterLength = 0; 197 size_t currPos, nextPos; 198 currPos = 0; 199 nextPos = size(); 200 for(unsigned int i = 0; i < num_delimiters_; ++i) 201 { 202 size_t tempPos = find(delimiters_[i], currPos); 203 if((tempPos != String::npos) && (tempPos < nextPos)) 204 { 205 nextPos = tempPos; 206 delimiterLength = delimiters_[i].size(); 207 } 208 } 209 while(1) 210 { 211 if((nextPos == String::npos) || (nextPos == size())) 212 { 213 result.push_back(substr(currPos)); 214 break; 215 } 216 217 if(nextPos != currPos) 218 { 219 result.push_back(substr(currPos, nextPos - currPos)); 220 } 221 currPos = nextPos + delimiterLength; 222 nextPos = size(); 223 delimiterLength = 0; 224 for(unsigned int i = 0; i < num_delimiters_; ++i) 225 { 226 size_t tempPos = find(delimiters_[i], currPos); 227 if((tempPos != String::npos) && (tempPos < nextPos)) 228 { 229 nextPos = tempPos; 230 delimiterLength = delimiters_[i].size(); 231 } 232 } 233 } 234 } 235 return result; 236 } 237 238 vector<String> String::splitByString(const String& delimiter_) const 239 { 240 return split(&delimiter_, 1); 241 } 242 243 bool String::contain(const String& str_) const 244 { 245 return (find(str_) != String::npos); 246 } 247 248 const char* String::toCString() const 249 { 250 return this->c_str(); 251 } 252 253 int String::toInt() const 254 { 255 return fromString<int>(*this); 256 } 257 258 unsigned int String::toUInt() const 259 { 260 return fromString<unsigned int>(*this); 261 } 262 263 long String::toLong() const 264 { 265 return fromString<long>(*this); 266 } 267 268 unsigned long String::toULong() const 269 { 270 return fromString<unsigned long>(*this); 271 } 272 273 float String::toFloat() const 274 { 275 return fromString<float>(*this); 276 } 277 278 double String::toDouble() const 279 { 280 return fromString<double>(*this); 281 } 282 283 bool String::toBool() const 284 { 285 return fromString<bool>(*this); 286 } 287 288 String::operator const char*() const 289 { 290 return this->c_str(); 291 } 292 293 String::operator int() const 294 { 295 return fromString<int>(*this); 296 } 297 298 String::operator unsigned int() const 299 { 300 return fromString<unsigned int>(*this); 301 } 302 303 String::operator long() const 304 { 305 return fromString<long>(*this); 306 } 307 308 String::operator unsigned long() const 309 { 310 return fromString<unsigned long>(*this); 311 } 312 313 String::operator float() const 314 { 315 return fromString<float>(*this); 316 } 317 318 String::operator double() const 319 { 320 return fromString<double>(*this); 321 } 322 323 String::operator bool() const 324 { 325 return fromString<bool>(*this); 326 } 327 328 String& String::operator=(char c_) 329 { 330 this->assign(1, c_); 331 return *this; 332 } 333 334 std::istream& safeGetline(std::istream& is_, String& str_) 335 { 336 str_.clear(); 337 338 // The characters in the stream are read one-by-one using a std::streambuf. 339 // That is faster than reading them one-by-one using the std::istream. 340 // Code that uses streambuf this way must be guarded by a sentry object. 341 // The sentry object performs various tasks, 342 // such as thread synchronization and updating the stream state. 343 344 std::istream::sentry se(is_, true); 345 std::streambuf* sb = is_.rdbuf(); 346 347 while(1) 348 { 349 int c = sb->sbumpc(); 350 switch(c) 351 { 352 case '\r': 353 c = sb->sgetc(); 354 if(c == '\n') 355 sb->sbumpc(); 356 return is_; 357 case '\n': 358 return is_; 359 case EOF: 360 is_.setstate(std::ios_base::failbit|std::ios_base::eofbit); 361 return is_; 362 default: 363 str_ += String(1, (char)c); 364 } 365 } 366 } 367} // namespace LibUtil 368 369