blocxx

StringBuffer.cpp

Go to the documentation of this file.
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