blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Vintela, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00039 #include "blocxx/BLOCXX_config.h" 00040 #include "blocxx/StringBuffer.hpp" 00041 #include "blocxx/Char16.hpp" 00042 00043 #include <cstring> 00044 #include <cstdio> 00045 #include <cctype> 00046 #if defined(BLOCXX_HAVE_ISTREAM) && defined(BLOCXX_HAVE_OSTREAM) 00047 #include <istream> 00048 #include <ostream> 00049 #else 00050 #include <iostream> 00051 #endif 00052 #include <algorithm> // for std::swap 00053 #include <cfloat> // for DBL_MANT_DIG 00054 00055 namespace BLOCXX_NAMESPACE 00056 { 00057 00058 #if defined(BLOCXX_AIX) 00059 const size_t StringBuffer::BLOCXX_DEFAULT_ALLOCATION_UNIT = 128; 00060 #endif // BLOCXX_AIX 00061 00062 StringBuffer::StringBuffer(size_t allocSize) : 00063 m_len(0), 00064 m_allocated(allocSize > 0 ? allocSize : BLOCXX_DEFAULT_ALLOCATION_UNIT), 00065 m_bfr(new char[m_allocated]) 00066 { 00067 m_bfr[0] = 0; 00068 } 00070 StringBuffer::StringBuffer(const char* arg) : 00071 m_len(strlen(arg)), 00072 m_allocated(m_len + BLOCXX_DEFAULT_ALLOCATION_UNIT), 00073 m_bfr(new char[m_allocated]) 00074 { 00075 ::strcpy(m_bfr, arg); 00076 } 00078 StringBuffer::StringBuffer(const String& arg) : 00079 m_len(arg.length()), 00080 m_allocated(m_len + BLOCXX_DEFAULT_ALLOCATION_UNIT), 00081 m_bfr(new char[m_allocated]) 00082 { 00083 ::strcpy(m_bfr, arg.c_str()); 00084 } 00086 StringBuffer::StringBuffer(const StringBuffer& arg) : 00087 m_len(arg.m_len), m_allocated(arg.m_allocated), 00088 m_bfr(new char[arg.m_allocated]) 00089 { 00090 ::memmove(m_bfr, arg.m_bfr, arg.m_len + 1); 00091 } 00093 StringBuffer& 00094 StringBuffer::operator= (const String& arg) 00095 { 00096 StringBuffer(arg).swap(*this); 00097 return *this; 00098 } 00100 StringBuffer& 00101 StringBuffer::operator= (const char* str) 00102 { 00103 StringBuffer(str).swap(*this); 00104 return *this; 00105 } 00107 StringBuffer& 00108 StringBuffer::operator =(const StringBuffer& arg) 00109 { 00110 StringBuffer(arg).swap(*this); 00111 return *this; 00112 } 00114 void 00115 StringBuffer::swap(StringBuffer& x) 00116 { 00117 std::swap(m_len, x.m_len); 00118 std::swap(m_allocated, x.m_allocated); 00119 std::swap(m_bfr, x.m_bfr); 00120 } 00122 void 00123 StringBuffer::reset() 00124 { 00125 m_len = 0; 00126 m_bfr[0] = '\0'; 00127 } 00128 00130 void 00131 StringBuffer::truncate(size_t index) 00132 { 00133 if (index < m_len) 00134 { 00135 m_bfr[index] = '\0'; 00136 m_len = index; 00137 } 00138 } 00139 00141 char 00142 StringBuffer::operator[] (size_t ndx) const 00143 { 00144 return (ndx > m_len) ? 0 : m_bfr[ndx]; 00145 } 00147 // This operator must write "TRUE"/"FALSE" to StringBuffer 00148 StringBuffer& 00149 StringBuffer::operator += (Bool v) 00150 { 00151 return append(v.toString()); 00152 } 00153 #if defined(BLOCXX_WIN32) 00154 #define snprintf _snprintf // stupid windoze... 00155 #endif 00156 00157 StringBuffer& 00158 StringBuffer::operator += (UInt8 v) 00159 { 00160 char bfr[6]; 00161 ::snprintf(bfr, sizeof(bfr), "%u", UInt32(v)); 00162 return append(bfr); 00163 } 00165 StringBuffer& 00166 StringBuffer::operator += (Int8 v) 00167 { 00168 char bfr[6]; 00169 ::snprintf(bfr, sizeof(bfr), "%d", Int32(v)); 00170 return append(bfr); 00171 } 00173 StringBuffer& 00174 StringBuffer::operator += (UInt16 v) 00175 { 00176 char bfr[16]; 00177 ::snprintf(bfr, sizeof(bfr), "%u", UInt32(v)); 00178 return append(bfr); 00179 } 00181 StringBuffer& 00182 StringBuffer::operator += (Int16 v) 00183 { 00184 char bfr[16]; 00185 ::snprintf(bfr, sizeof(bfr), "%d", Int32(v)); 00186 return append(bfr); 00187 } 00189 StringBuffer& 00190 StringBuffer::operator += (UInt32 v) 00191 { 00192 char bfr[16]; 00193 ::snprintf(bfr, sizeof(bfr), "%u", v); 00194 return append(bfr); 00195 } 00197 StringBuffer& 00198 StringBuffer::operator += (Int32 v) 00199 { 00200 char bfr[16]; 00201 ::snprintf(bfr, sizeof(bfr), "%d", v); 00202 return append(bfr); 00203 } 00204 #if defined(BLOCXX_INT32_IS_INT) && defined(BLOCXX_INT64_IS_LONG_LONG) 00205 00206 StringBuffer& 00207 StringBuffer::operator += (unsigned long v) 00208 { 00209 char bfr[28]; 00210 ::snprintf(bfr, sizeof(bfr), "%lu", v); 00211 return append(bfr); 00212 } 00214 StringBuffer& 00215 StringBuffer::operator += (long v) 00216 { 00217 char bfr[28]; 00218 ::snprintf(bfr, sizeof(bfr), "%ld", v); 00219 return append(bfr); 00220 } 00221 #endif 00222 00223 StringBuffer& 00224 StringBuffer::operator += (UInt64 v) 00225 { 00226 char bfr[28]; 00227 #if BLOCXX_SIZEOF_LONG_INT == 8 00228 ::snprintf(bfr, sizeof(bfr), "%lu", v); 00229 #else 00230 ::snprintf(bfr, sizeof(bfr), "%llu", v); 00231 #endif 00232 return append(bfr); 00233 } 00235 StringBuffer& 00236 StringBuffer::operator += (Int64 v) 00237 { 00238 char bfr[28]; 00239 #if BLOCXX_SIZEOF_LONG_INT == 8 00240 ::snprintf(bfr, sizeof(bfr), "%ld", v); 00241 #else 00242 ::snprintf(bfr, sizeof(bfr), "%lld", v); 00243 #endif 00244 return append(bfr); 00245 } 00247 // decimal digits = ceiling((bits)*ln(2)/ln(10)) 00248 StringBuffer& 00249 StringBuffer::operator += (Real32 v) 00250 { 00251 char bfr[128]; 00252 #if FLT_RADIX == 2 00253 #if defined(BLOCXX_REAL32_IS_FLOAT) 00254 ::snprintf(bfr, sizeof(bfr), "%.*g", FLT_MANT_DIG * 3 / 10 + 1, static_cast<double>(v)); 00255 #elif defined(BLOCXX_REAL32_IS_DOUBLE) 00256 ::snprintf(bfr, sizeof(bfr), "%.*g", DBL_MANT_DIG * 3 / 10 + 1, v); 00257 #endif 00258 #else 00259 #error "The formula for computing the number of digits of precision for a floating point needs to be implmented. It's ceiling(bits * log(FLT_RADIX) / log(10))" 00260 #endif 00261 return append(bfr); 00262 } 00264 StringBuffer& 00265 StringBuffer::operator += (Real64 v) 00266 { 00267 char bfr[32]; 00268 #if FLT_RADIX == 2 00269 #if defined(BLOCXX_REAL64_IS_DOUBLE) 00270 ::snprintf(bfr, sizeof(bfr), "%.*g", DBL_MANT_DIG * 3 / 10 + 1, v); 00271 #elif defined(BLOCXX_REAL64_IS_LONG_DOUBLE) 00272 ::snprintf(bfr, sizeof(bfr), "%.*Lg", LDBL_MANT_DIG * 3 / 10 + 1, v); 00273 #endif 00274 #else 00275 #error "The formula for computing the number of digits of precision for a floating point needs to be implmented. It's ceiling(bits * log(FLT_RADIX) / log(10))" 00276 #endif 00277 return append(bfr); 00278 } 00279 #if defined(BLOCXX_WIN32) 00280 #undef snprintf 00281 #endif 00282 00283 StringBuffer& 00284 StringBuffer::append(const char* str, const size_t len) 00285 { 00286 checkAvail(len+1); 00287 ::strncpy(m_bfr+m_len, str, len); 00288 m_len += len; 00289 m_bfr[m_len] = '\0'; 00290 return *this; 00291 } 00293 bool 00294 StringBuffer::equals(const char* arg) const 00295 { 00296 return ::strcmp(arg, m_bfr) == 0; 00297 } 00298 00300 bool 00301 StringBuffer::equals(const StringBuffer& arg) const 00302 { 00303 return ::strcmp(arg.m_bfr, m_bfr) == 0; 00304 } 00305 00307 bool 00308 StringBuffer::endsWith(char ch) const 00309 { 00310 return (m_len && m_bfr[m_len-1] == ch); 00311 } 00312 00314 bool 00315 StringBuffer::startsWith(char ch) const 00316 { 00317 return (m_len && m_bfr[0] == ch); 00318 } 00319 00321 void 00322 StringBuffer::chop() 00323 { 00324 if (m_len) 00325 { 00326 truncate(m_len-1); 00327 } 00328 } 00329 00331 void 00332 StringBuffer::trim() 00333 { 00334 if (m_len) 00335 { 00336 while (m_len && isspace(m_bfr[m_len-1])) 00337 { 00338 m_bfr[--m_len] = 0; 00339 } 00340 00341 if (m_len) 00342 { 00343 char *p = m_bfr; 00344 while (*p && isspace(*p)) 00345 { 00346 ++p; 00347 } 00348 00349 if (*p && p > m_bfr) 00350 { 00351 m_len -= (p - m_bfr); 00352 memmove(m_bfr, p, m_len+1); 00353 } 00354 } 00355 } 00356 } 00357 00359 // Get one line from an input stream. This StringBuffer object will be 00360 // reset (cleared) before an attempt is made to retrieve the line. 00361 const char* 00362 StringBuffer::getLine(std::istream& is, bool resetBuffer) 00363 { 00364 if (resetBuffer) 00365 { 00366 reset(); 00367 } 00368 00369 if (is) 00370 { 00371 size_t count = 0; 00372 std::streambuf *sb = is.rdbuf(); 00373 00374 while (1) 00375 { 00376 int ch = sb->sbumpc(); 00377 if (ch == EOF) 00378 { 00379 is.setstate(count == 0 00380 ? (std::ios::failbit | std::ios::eofbit) : std::ios::eofbit); 00381 break; 00382 } 00383 00384 ++count; 00385 00386 if (ch == '\n') 00387 { 00388 break; 00389 } 00390 00391 append(static_cast<char>(ch)); 00392 } 00393 } 00394 00395 const char* p = ::strchr(m_bfr, '\r'); 00396 if (p) 00397 { 00398 truncate(size_t(p-m_bfr)); 00399 } 00400 00401 return m_bfr; 00402 } 00403 00405 std::ostream& operator<<(std::ostream& ostr, const StringBuffer& b) 00406 { 00407 ostr.write(b.c_str(), b.length()); 00408 return ostr; 00409 } 00410 00412 bool operator==(const StringBuffer& x, const StringBuffer& y) 00413 { 00414 return x.equals(y); 00415 } 00416 00418 bool operator!=(const StringBuffer& x, const StringBuffer& y) 00419 { 00420 return !(x == y); 00421 } 00422 00424 bool operator==(const StringBuffer& x, const String& y) 00425 { 00426 return x.equals(y.c_str()); 00427 } 00428 00430 bool operator!=(const StringBuffer& x, const String& y) 00431 { 00432 return !(x == y); 00433 } 00434 00436 bool operator==(const String& x, const StringBuffer& y) 00437 { 00438 return x.equals(y.c_str()); 00439 } 00440 00442 bool operator!=(const String& x, const StringBuffer& y) 00443 { 00444 return !(x == y); 00445 } 00446 00447 } // end namespace BLOCXX_NAMESPACE 00448