Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlCore/String.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2011, Michele Bosi                                             */
00007 /*  All rights reserved.                                                              */
00008 /*                                                                                    */
00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
00010 /*  are permitted provided that the following conditions are met:                     */
00011 /*                                                                                    */
00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
00013 /*  list of conditions and the following disclaimer.                                  */
00014 /*                                                                                    */
00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
00017 /*  other materials provided with the distribution.                                   */
00018 /*                                                                                    */
00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
00029 /*                                                                                    */
00030 /**************************************************************************************/
00031 
00032 #include <vlCore/String.hpp>
00033 #include <vlCore/String_Tables.hpp>
00034 #include <vlCore/Log.hpp>
00035 #include <vlCore/Say.hpp>
00036 #include <vlCore/FileSystem.hpp>
00037 #include <vlCore/VirtualFile.hpp>
00038 #include <vlCore/VisualizationLibrary.hpp>
00039 #include <stdio.h>
00040 #include <stdarg.h>
00041 
00042 using namespace vl;
00043 
00044 //-----------------------------------------------------------------------------
00045 // String
00046 //-----------------------------------------------------------------------------
00047 String::String()
00048 {
00049 #if VL_STRING_COPY_ON_WRITE == 0
00050   acquireData();
00051 #endif
00052 }
00053 //-----------------------------------------------------------------------------
00054 String::String(const String& other)
00055 {
00056   operator=(other);
00057 }
00058 //-----------------------------------------------------------------------------
00059 String::String(const wchar_t* wstr)
00060 {
00061 #if VL_STRING_COPY_ON_WRITE == 0
00062   acquireData();
00063 #endif
00064   if (wstr)
00065     *this = wstr;
00066 }
00067 //-----------------------------------------------------------------------------
00068 String::String(const char* str)
00069 {
00070 #if VL_STRING_COPY_ON_WRITE == 0
00071   acquireData();
00072 #endif
00073   if (str)
00074     *this = str;
00075 }
00076 //-----------------------------------------------------------------------------
00077 String::String(wchar_t ch, int count)
00078 {
00079 #if VL_STRING_COPY_ON_WRITE == 0
00080   acquireData();
00081 #endif
00082   for(int i=0; i<count; ++i)
00083     *this += ch;
00084 }
00085 //-----------------------------------------------------------------------------
00086 String String::loadText(const String& path, EStringEncoding default_encoding)
00087 {
00088   ref<VirtualFile> file = defFileSystem()->locateFile(path);
00089   if (file)
00090     return loadText( file.get(), default_encoding );
00091   else
00092   {
00093     Log::error( Say("Could not locate '%s'.\n") << path );
00094     return String();
00095   }
00096 }
00097 //-----------------------------------------------------------------------------
00098 String String::loadText(VirtualFile* file, EStringEncoding default_encoding)
00099 {
00100   std::vector<char> buffer;
00101   file->load( buffer );
00102   file->close();
00103 
00104   if ( buffer.size() )
00105   {
00106     return loadText( &buffer[0], (int)buffer.size(), default_encoding );
00107   }
00108   else
00109   {
00110     return String();
00111   }
00112 }
00113 //-----------------------------------------------------------------------------
00114 String String::loadText(void* data, int bytes, EStringEncoding default_encoding )
00115 {
00116   EStringEncoding enc = detectEncoding( data, bytes, default_encoding );
00117   String text;
00118   switch(enc)
00119   {
00120     case SE_ASCII:
00121       return fromAscii((char*)data, bytes);
00122       break;
00123     case SE_LATIN1:
00124       return fromLatin1((char*)data, bytes);
00125       break;
00126     case SE_UTF8:
00127       return fromUTF8((char*)data, bytes);
00128       break;
00129     case SE_UTF16_BE:
00130       return fromUTF16BE((unsigned short*)data, bytes );
00131       break;
00132     case SE_UTF16_LE:
00133       return fromUTF16LE((unsigned short*)data, bytes );
00134       break;
00135     case SE_Unknown:
00136       Log::error("String::loadText() unknown encoding.\n");
00137       break;
00138     case SE_UTF32_BE:
00139     case SE_UTF32_LE:
00140       Log::error("String::loadText() SE_UTF32_BE/SE_UTF32_LE encoding not supported.\n");
00141       break;
00142   }
00143   return String();
00144 }
00145 //-----------------------------------------------------------------------------
00146 String& String::resize(int character_count)
00147 {
00148   acquireData();
00149   mString->resize(character_count);
00150   return *this;
00151 }
00152 //-----------------------------------------------------------------------------
00153 String String::substring(int start, int count) const
00154 {
00155   // createData();
00156   if ( empty() )
00157     return String();
00158 
00159   if (start<0)
00160     start = 0;
00161   if (count<0)
00162     count = length();
00163   int end_idx = start+count-1;
00164   if (end_idx > length()-1 )
00165     end_idx = length()-1;
00166 
00167   String str;
00168   str.acquireData();
00169   int sz = end_idx - start + 1;
00170   sz = sz < 0 ? 0 : sz;
00171   str.mString->resize( sz );
00172   for(int i=0; i<(int)str.mString->length(); ++i)
00173     (*str.mString)[i] = (*mString)[start+i];
00174   return str;
00175 }
00176 //-----------------------------------------------------------------------------
00177 int String::findBackwards(wchar_t ch) const
00178 {
00179   // createData();
00180   if (empty())
00181     return -1;
00182 
00183   for(int i=length(); i--; )
00184     if ((*mString)[i] == ch)
00185       return i;
00186   return -1;
00187 }
00188 //-----------------------------------------------------------------------------
00189 int String::findBackwards(const String& str) const
00190 {
00191   // createData();
00192   if (empty())
00193     return -1;
00194 
00195   if (str.length() < length())
00196   {
00197     for(int i = length() - str.length()+1; i--; )
00198     {
00199       int j=0;
00200       for(; j<str.length(); ++j)
00201       {
00202         if ( str[j] != (*mString)[i+j] )
00203           break;
00204       }
00205       if ( j == str.length() )
00206         return i;
00207     }
00208   }
00209   return -1;
00210 }
00211 //-----------------------------------------------------------------------------
00212 bool String::contains(wchar_t ch) const
00213 {
00214   return find(ch) != -1;
00215 }
00216 //-----------------------------------------------------------------------------
00217 int String::find(wchar_t ch, int start) const
00218 {
00219   // createData();
00220   if (empty())
00221     return -1;
00222 
00223   for(int i=start; i<length(); ++i)
00224     if ((*mString)[i] == ch)
00225       return i;
00226   return -1;
00227 }
00228 //-----------------------------------------------------------------------------
00229 bool String::contains(const String& substr) const
00230 {
00231   return find(substr) != -1;
00232 }
00233 //-----------------------------------------------------------------------------
00234 namespace
00235 {
00236   // warning: this function takes 256K on the stack!
00237   int String_Quick_Search(const wchar_t*x, int m, const wchar_t*y, int n)
00238   {
00239     int qsBc[0x10000];
00240     for (int i = 0; i < 0x10000; ++i)
00241       qsBc[i] = m + 1;
00242     for (int i = 0; i < m; ++i)
00243       qsBc[x[i]] = m - i;
00244     for(int j=0; j <= n - m; j += qsBc[y[j + m]] )
00245       if (memcmp(x, y + j, m*sizeof(wchar_t)) == 0)
00246          return j;
00247     return -1;
00248   }
00249 }
00250 //-----------------------------------------------------------------------------
00251 int String::findInLargeText(const String& substr, int start) const
00252 {
00253   // createData();
00254   if (empty())
00255     return -1;
00256 
00257   if ( substr.length() > length() || start >= length() || substr.empty() || empty() )
00258     return -1;
00259   {
00260     int pos = String_Quick_Search( &(*substr.mString)[0], substr.length(), &(*mString)[0]+start, length()-start );
00261     return pos >= 0 ? pos + start : pos;
00262   }
00263 }
00264 //-----------------------------------------------------------------------------
00265 int String::find(const String& substr, int start) const
00266 {
00267   // createData();
00268   if (empty())
00269     return -1;
00270 
00271   if ( substr.length() > length() || start >= length() || substr.empty() || empty() )
00272     return -1;
00273   {
00274     int max = length() - substr.length();
00275     for(int i=start; i<=max; ++i)
00276     {
00277       int j=0;
00278       for(; j<substr.length(); ++j)
00279       {
00280         if (substr[j] != (*mString)[i+j])
00281           break;
00282       }
00283       if (j == substr.length())
00284         return i;
00285     }
00286     return -1;
00287   }
00288 }
00289 //-----------------------------------------------------------------------------
00290 void String::squeeze()
00291 {
00292   if(empty())
00293     return;
00294 
00295   mString->squeeze();
00296 }
00297 //-----------------------------------------------------------------------------
00298 String& String::fill(wchar_t ch)
00299 {
00300   acquireData();
00301 
00302   for(int i=0; i<length(); ++i)
00303     (*mString)[i] = ch;
00304   return *this;
00305 }
00306 //-----------------------------------------------------------------------------
00307 String& String::trim(const String& chars)
00308 {
00309   acquireData();
00310 
00311   while( chars.length() )
00312   {
00313     int len = length();
00314     for( int i=0; i<chars.length(); ++i)
00315       trim(chars[i]);
00316     if ( len == length())
00317       break;
00318   }
00319   return *this;
00320 }
00321 //-----------------------------------------------------------------------------
00322 String& String::trim(wchar_t ch)
00323 {
00324   acquireData();
00325 
00326   if (length())
00327   {
00328     int pos = 0;
00329     while( (*mString)[pos] == ch )
00330       pos++;
00331     if (pos)
00332       *this = substring(pos);
00333     pos = length()-1;
00334     while( pos >=0 && (*mString)[pos] == ch )
00335       pos--;
00336     pos++;
00337     if (pos != length())
00338       *this = substring(0,pos);
00339   }
00340   return *this;
00341 }
00342 //-----------------------------------------------------------------------------
00343 String& String::trim()
00344 {
00345   acquireData();
00346 
00347   trim("\n\r\t\v ");
00348 
00349   return *this;
00350 }
00351 //-----------------------------------------------------------------------------
00352 void String::split(const String& separator_list, std::vector<String>& fields, bool remove_empty) const
00353 {
00354   fields.clear();
00355 
00356   // createData();
00357   if (empty())
00358     return;
00359 
00360   if ( length() )
00361   {
00362     fields.push_back( String() );
00363     fields.back().acquireData();
00364     fields.back().mString->clear();
00365     for(int i=0; i<length(); ++i)
00366     {
00367       if ( separator_list.contains((*mString)[i]) )
00368       {
00369         fields.push_back( String() );
00370         fields.back().acquireData();
00371         fields.back().mString->clear();
00372         continue;
00373       }
00374       fields.back().mString->push_back( (*mString)[i] );
00375     }
00376   }
00377 
00378   if (remove_empty)
00379   {
00380     for ( size_t i=fields.size(); i--; )
00381       if (fields[i].empty())
00382         fields.erase(fields.begin() + i);
00383   }
00384 }
00385 //-----------------------------------------------------------------------------
00386 void String::split(wchar_t separator, std::vector<String>& fields, bool remove_empty) const
00387 {
00388   fields.clear();
00389 
00390   // createData();
00391   if (empty())
00392     return;
00393 
00394   if ( length() )
00395   {
00396     fields.push_back( String() );
00397     fields.back().acquireData();
00398     fields.back().mString->clear();
00399     for(int i=0; i<length(); ++i)
00400     {
00401       if ((*mString)[i] == separator)
00402       {
00403         fields.push_back( String() );
00404         fields.back().acquireData();
00405         fields.back().mString->clear();
00406         continue;
00407       }
00408       fields.back().mString->push_back( (*mString)[i] );
00409     }
00410   }
00411 
00412   if (remove_empty)
00413   {
00414     for ( size_t i=fields.size(); i--; )
00415       if (fields[i].empty())
00416         fields.erase(fields.begin() + i);
00417   }
00418 }
00419 //-----------------------------------------------------------------------------
00420 void String::splitLines(std::vector<String>& lines) const
00421 {
00422   lines.clear();
00423 
00424   // createData();
00425   if (empty())
00426     return;
00427 
00428   if ( length() )
00429   {
00430     lines.push_back( String() );
00431     lines.back().acquireData();
00432     lines.back().mString->clear();
00433     for(int i=0; i<length(); ++i)
00434     {
00435       if ((*mString)[i] == '\n' || (*mString)[i] == '\r')
00436       {
00437         lines.push_back( String() );
00438         lines.back().acquireData();
00439         lines.back().mString->clear();
00440         // no need to check i+1<lenght()-1 since the buffer is 0 terminated
00441         if ((*mString)[i] == '\n' && (*mString)[i+1] == '\r')
00442           ++i;
00443         else
00444         if ((*mString)[i] == '\r' && (*mString)[i+1] == '\n')
00445           ++i;
00446         continue;
00447       }
00448       lines.back().mString->push_back( (*mString)[i] );
00449     }
00450   }
00451 }
00452 //-----------------------------------------------------------------------------
00453 String String::field(wchar_t separator, int field_index) const
00454 {
00455   String field;
00456   int field_count = 0;
00457   int i=0;
00458   for(; i<length() && field_count<field_index; ++i)
00459   {
00460     if ( (*this)[i] == separator )
00461       ++field_count;
00462   }
00463   // fill field data
00464   for(; i<length() && (*this)[i] != separator; ++i)
00465     field+=(*this)[i];
00466   return field;
00467 }
00468 //-----------------------------------------------------------------------------
00469 String& String::remove(const String& str, int start, int count)
00470 {
00471   acquireData();
00472 
00473   if (count == 0)
00474     return *this;
00475   if (count<0)
00476     count = length();
00477   int removed = 0;
00478   for( int pos = find(str, start); pos != -1 && removed<count; start=pos, pos=find(str, start), ++removed)
00479     remove( pos, str.length() );
00480   return *this;
00481 }
00482 //-----------------------------------------------------------------------------
00483 String& String::remove( int start, int count )
00484 {
00485   if (count == 0)
00486     return *this;
00487 
00488   acquireData();
00489 
00490   String tmp;
00491   tmp.acquireData();
00492   tmp.mString->clear();
00493   int end = start + count-1;
00494   for( int i=0; i<length(); i++ )
00495     if (i<start || i>end)
00496       tmp.mString->push_back((*mString)[i]);
00497   /*tmp.mString->push_back(0);*/
00498   mString = tmp.mString;
00499   return *this;
00500 }
00501 //-----------------------------------------------------------------------------
00502 String& String::remove(wchar_t ch, int start, int count)
00503 {
00504   acquireData();
00505 
00506   if (count<0)
00507     count = length();
00508   String tmp = *this;
00509   tmp.acquireData();
00510   mString->clear();
00511   int removed = 0;
00512   for(int i=0; i<tmp.length(); ++i)
00513     if ( tmp[i]!=ch || removed==count || i<start)
00514       mString->push_back( tmp[i] );
00515     else
00516       ++removed;
00517   /*mString->push_back(0);*/
00518   return *this;
00519 }
00520 //-----------------------------------------------------------------------------
00521 String& String::reverse()
00522 {
00523   acquireData();
00524   int count = length() / 2;
00525   for(int i=0; i<count; ++i)
00526   {
00527     wchar_t tmp = (*this)[i];
00528     (*this)[i] = (*this)[length() - 1 - i];
00529     (*this)[length() - 1 - i] = tmp;
00530   }
00531   return *this;
00532 }
00533 //-----------------------------------------------------------------------------
00534 String& String::normalizeSlashes() 
00535 { 
00536   // convert all '\' to '/'
00537   replace('\\', '/');
00538   // remove double slashes
00539   int len=0;
00540   do
00541   {
00542     len=length();
00543     replace("//", "/"); 
00544   }
00545   while(len!=length());
00546 
00547   bool beg_slash = startsWith('/');
00548 
00549   bool end_slash = endsWith('/');
00550 
00551   // resolve . and ..
00552   std::vector<String> parts;
00553   split('/', parts, true);
00554   std::vector<String> new_parts;
00555   for(size_t i=0; i<parts.size(); ++i)
00556   {
00557     if (parts[i] == ".")
00558       continue;
00559     else
00560     if (parts[i] == ".." && !new_parts.empty())
00561     {
00562       new_parts.pop_back();
00563       continue;
00564     }
00565     else
00566       new_parts.push_back(parts[i]);
00567   }
00568 
00569   // recreate the string
00570 
00571   clear();
00572   if (beg_slash)
00573     *this += '/';
00574 
00575   for(size_t i=0; i<new_parts.size(); ++i)
00576   {
00577     *this += new_parts[i];
00578     if(i != new_parts.size()-1)
00579       *this += '/';
00580   }
00581 
00582   if (end_slash)
00583     *this += '/';
00584 
00585   return *this; 
00586 }
00587 //-----------------------------------------------------------------------------
00588 String& String::append(wchar_t ch, int count)
00589 {
00590   acquireData();
00591 
00592   for(int i=0; i<count; ++i)
00593     mString->push_back(ch);
00594   return *this;
00595 }
00596 //-----------------------------------------------------------------------------
00597 String& String::append(const String& other)
00598 {
00599   acquireData();
00600 
00601   for(int i=0; i<other.length(); ++i)
00602     mString->push_back(other[i]);
00603   return *this;
00604 }
00605 //-----------------------------------------------------------------------------
00606 String& String::prepend(const String& str)
00607 {
00608   return insert(0, str);
00609 }
00610 //-----------------------------------------------------------------------------
00611 String& String::prepend(wchar_t ch, int count)
00612 {
00613   return insert(0, ch, count);
00614 }
00615 //-----------------------------------------------------------------------------
00616 String& String::replace( int start, int count, const String& str )
00617 {
00618   remove(start, count);
00619   insert(start, str);
00620   return *this;
00621 }
00622 //-----------------------------------------------------------------------------
00623 String& String::replace( const String& oldstr, const String& newstr, bool case_sensitive )
00624 {
00625   acquireData();
00626   String supstr = case_sensitive ? *this  : toLowerCase();
00627   String substr = case_sensitive ? oldstr : oldstr.toLowerCase();
00628 
00629   std::vector<int> positions;
00630   for( int pos = 0; (pos=supstr.find(substr,pos)) != -1; pos += substr.length() )
00631     positions.push_back(pos);
00632 
00633   // replace backwards to support new/old string of different sizes
00634   for(unsigned i=positions.size(); i--; )
00635     replace(positions[i], oldstr.length(), newstr);
00636 
00637   return *this;
00638 }
00639 //-----------------------------------------------------------------------------
00640 String& String::replace( int start, int count, wchar_t ch )
00641 {
00642   acquireData();
00643 
00644   if (start < 0 )
00645     start = 0;
00646   if (count < 0)
00647     count = length();
00648   int end = start + count;
00649   if (end > length())
00650     end = length();
00651   for(int i=start; i<end; ++i)
00652     (*mString)[i] = ch;
00653   return *this;
00654 }
00655 //-----------------------------------------------------------------------------
00656 String& String::replace( wchar_t old_ch, wchar_t new_ch )
00657 {
00658   acquireData();
00659 
00660   for(int i=0; i<length(); ++i)
00661     if ((*mString)[i] == old_ch)
00662       (*mString)[i] = new_ch;
00663   return *this;
00664 }
00665 //-----------------------------------------------------------------------------
00666 int String::count(wchar_t ch, int start) const
00667 {
00668   // createData();
00669   if (empty())
00670     return 0;
00671 
00672   int num = 0;
00673   for(int i=start; i<length(); ++i)
00674     if ((*mString)[i] == ch)
00675       ++num;
00676   return num;
00677 }
00678 //-----------------------------------------------------------------------------
00679 int String::count(const String& str, int start) const
00680 {
00681   // createData();
00682   if (empty())
00683     return 0;
00684 
00685   int found = 0;
00686   for( int pos = find(str, start); pos != -1; start=pos+str.length(), pos=find(str, start))
00687     ++found;
00688   return found;
00689 }
00690 //-----------------------------------------------------------------------------
00691 int String::compare(const String& other) const
00692 {
00693   createData();
00694 
00695   int min = length() < other.length() ? length() : other.length();
00696   for(int i=0; i<min; ++i)
00697   {
00698     if ( (*mString)[i] != (*other.mString)[i] )
00699       return (int)(*mString)[i] - (int)(*other.mString)[i];
00700   }
00701   // their common subsection is equal, shortest goes first
00702   return length() - other.length();
00703 }
00704 //-----------------------------------------------------------------------------
00705 bool String::endsWith(const String& str) const
00706 {
00707   //createData();
00708   if (empty())
00709     return false;
00710 
00711   if (length() < str.length() || empty() || str.empty() )
00712     return false;
00713   else
00714   {
00715     int offset = length() - str.length();
00716     return memcmp( &(*mString)[0] + offset, &(*str.mString)[0], sizeof((*mString)[0])*str.length() ) == 0;
00717   }
00718 }
00719 //-----------------------------------------------------------------------------
00720 bool String::startsWith(const String& str) const
00721 {
00722   //createData();
00723   if (str.empty())
00724     return true;
00725 
00726   if (empty())
00727     return false;
00728 
00729   if (length() < str.length() || empty() || str.empty() )
00730     return false;
00731   else
00732   {
00733     return memcmp( &(*mString)[0], &(*str.mString)[0], sizeof((*mString)[0])*str.length() ) == 0;
00734   }
00735 }
00736 //-----------------------------------------------------------------------------
00737 bool String::endsWith(wchar_t ch) const
00738 {
00739   //createData();
00740   if (empty())
00741     return false;
00742 
00743   return length() > 0 && (*mString)[length()-1] == ch;
00744 }
00745 //-----------------------------------------------------------------------------
00746 bool String::startsWith(wchar_t ch) const
00747 {
00748   //createData();
00749   if (empty())
00750     return false;
00751 
00752   return length() > 0 && (*mString)[0] == ch;
00753 }
00754 //-----------------------------------------------------------------------------
00755 String String::toLowerCase() const
00756 {
00757   //createData();
00758   if (empty())
00759     return String();
00760 
00761   String lower = *this;
00762   lower.acquireData();
00763   for(int i=0; i<length(); ++i)
00764     (*lower.mString)[i] = getLowerCase( (*lower.mString)[i] );
00765   return lower;
00766 }
00767 //-----------------------------------------------------------------------------
00768 String String::toUpperCase() const
00769 {
00770   //createData();
00771   if (empty())
00772     return String();
00773 
00774   String lower = *this;
00775   lower.acquireData();
00776   for(int i=0; i<length(); ++i)
00777     (*lower.mString)[i] = getUpperCase( (*lower.mString)[i] );
00778   return lower;
00779 }
00780 //-----------------------------------------------------------------------------
00781 String& String::insert(int pos, const String& str)
00782 {
00783   if (str.empty())
00784     return *this;
00785 
00786   acquireData();
00787 
00788   if (pos > length())
00789     return append(str);
00790   int remaining = length() - pos;
00791   mString->resize( mString->length() + str.length() );
00792   memmove( &(*mString)[0]+pos+str.length(), &(*mString)[0]+pos, sizeof(str[0])*remaining );
00793   memcpy( &(*mString)[0]+pos, &(*str.mString)[0], sizeof(str[0])*str.length() );
00794   return *this;
00795 }
00796 //-----------------------------------------------------------------------------
00797 String& String::insert(int pos, wchar_t ch, int count)
00798 {
00799   if (count == 0)
00800     return *this;
00801 
00802   acquireData();
00803 
00804   if (pos >= length())
00805     return append(ch, count);
00806   int remaining = length() - pos;
00807   mString->resize( mString->length() + count );
00808   memmove( &(*mString)[0]+pos+count, &(*mString)[0]+pos, sizeof((*mString)[0])*remaining );
00809   for(int i=0; i<count && i+pos<length(); ++i)
00810     (*mString)[i+pos] = ch;
00811   return *this;
00812 }
00813 //-----------------------------------------------------------------------------
00814 String String::left(int count) const
00815 {
00816   if (count<0)
00817     return substring(0, length()+count);
00818   else
00819     return substring(0, count);
00820 }
00821 //-----------------------------------------------------------------------------
00822 String String::right(int count) const
00823 {
00824   if (count<0)
00825     return substring(-count, length()+count);
00826   else
00827     return substring(length()-count, count);
00828 }
00829 //-----------------------------------------------------------------------------
00830 String String::extractPath() const
00831 {
00832   //createData();
00833   if (empty())
00834     return String();
00835 
00836   String path = *this;
00837   path.normalizeSlashes();
00838   int slash_pos = path.findBackwards('/');
00839   if (slash_pos<0)
00840     return String();
00841   else
00842     return path.substring(0,slash_pos+1);
00843 }
00844 //-----------------------------------------------------------------------------
00845 String String::extractFileName() const
00846 {
00847   //createData();
00848   if (empty())
00849     return String();
00850 
00851   int a = findBackwards('/');
00852   int b = findBackwards('\\');
00853   int slash_pos = a > b ? a : b;
00854   return substring(slash_pos+1);
00855 }
00856 //-----------------------------------------------------------------------------
00857 String String::extractFileExtension(bool require_dot) const
00858 {
00859   //createData();
00860   if (empty())
00861     return String();
00862 
00863   int dot_pos = findBackwards('.');
00864   if (require_dot && dot_pos == -1)
00865     return String();
00866   else
00867     return substring(dot_pos+1);
00868 }
00869 //-----------------------------------------------------------------------------
00870 String String::fromStdWString(const std::wstring& str)
00871 {
00872   String s;
00873   s.acquireData();
00874 
00875   s.mString->clear();
00876   for(int i=0; i<(int)str.length(); ++i)
00877     s.mString->push_back( str[i] );
00878   return s;
00879 }
00880 //-----------------------------------------------------------------------------
00881 String String::fromStdString(const std::string& str, bool utf8)
00882 {
00883   if (utf8)
00884     return fromUTF8( str.c_str(), str.length());
00885   else
00886     return fromAscii( str.c_str() );
00887 }
00888 //-----------------------------------------------------------------------------
00889 String String::fromAscii(const char* str, int size)
00890 {
00891   String s;
00892   s.acquireData();
00893 
00894   if (size<0)
00895     size = (int)strlen(str);
00896   const unsigned char* ascii = (const unsigned char*)str;
00897   s.mString->clear();
00898   for(int i=0; i<size; ++i)
00899   {
00900     if( ascii[i] < 128 )
00901       s.mString->push_back( ascii[i] );
00902     else
00903 
00904       s.mString->push_back( L'?' );
00905   }
00906   /*s.mString->push_back(0);*/
00907   return s;
00908 }
00909 //-----------------------------------------------------------------------------
00910 String String::fromUTF16BE(const unsigned short* str, int byte_count)
00911 {
00912   String s;
00913   s.acquireData();
00914 
00915   VL_COMPILE_TIME_CHECK( sizeof(unsigned short) == 2 )
00916   int character_count = byte_count < 0 ? -1 : byte_count / 2;
00917 
00918   // detect character_count
00919   if (character_count<0)
00920     for(character_count=0; str[character_count]; ) ++character_count;
00921 
00922   // skip header
00923   if (str[0] == 65534)
00924   {
00925     str++;
00926     --character_count;
00927   }
00928 
00929   s.mString->clear();
00930   for(int i=0; i<character_count; ++i)
00931   {
00932     const unsigned char* bytes = (const unsigned char*)(str+i);
00933     unsigned int code = bytes[1] + (bytes[0]<<8);
00934     // skip surrogate pair
00935     if (code>=0xD800 && code <=0xDC00)
00936     {
00937       s.mString->push_back( '?' );
00938       ++i;
00939     }
00940     else
00941       s.mString->push_back( (wchar_t)code );
00942   }
00943   return s;
00944 }
00945 //-----------------------------------------------------------------------------
00946 String String::fromUTF16LE(const unsigned short* str, int byte_count)
00947 {
00948   String s;
00949   s.acquireData();
00950 
00951   VL_COMPILE_TIME_CHECK( sizeof(unsigned short) == 2 )
00952   int character_count = byte_count < 0 ? -1 : byte_count / 2;
00953 
00954   // detect character_count
00955   if (character_count<0)
00956     for(character_count=0; str[character_count]; ) ++character_count;
00957 
00958   // skip header
00959   if (str[0] == 65279)
00960   {
00961     str++;
00962     --character_count;
00963   }
00964 
00965   s.mString->clear();
00966   for(int i=0; i<character_count; ++i)
00967   {
00968     unsigned char* bytes = (unsigned char*)(str+i);
00969     unsigned int code = bytes[0] + (bytes[1]<<8);
00970     // skip surrogate pair
00971     if (code>=0xD800 && code <=0xDC00)
00972     {
00973       s.mString->push_back( '?' );
00974       ++i;
00975     }
00976     else
00977       s.mString->push_back( (wchar_t)code );
00978   }
00979   return s;
00980 }
00981 //-----------------------------------------------------------------------------
00982 String String::fromUTF16(const unsigned short* str, int byte_count)
00983 {
00984   String s;
00985   s.acquireData();
00986 
00987   if (str[0] == 65279)
00988     s = fromUTF16LE(str, byte_count);
00989   else
00990   if (str[0] == 65534)
00991     s = fromUTF16BE(str, byte_count);
00992   else
00993   {
00994     Log::error("String::fromUTF16(): not UTF16 BE nor LE found.\n");
00995     s.clear();
00996   }
00997   return s;
00998 }
00999 //-----------------------------------------------------------------------------
01000 String String::fromUTF8(const char* str, int byte_count)
01001 {
01002   String s;
01003   s.acquireData();
01004 
01005   unsigned char* utf8 = (unsigned char*)str;
01006   int start=0;
01007   // skip header EF BB BF if present
01008   if ( utf8[0] == 0xEF && utf8[1] == 0xBB && utf8[2] == 0xBF )
01009     start=3;
01010   // detect size
01011   if (byte_count<0)
01012     for(byte_count=0; utf8[byte_count]; ) ++byte_count;
01013 
01014   s.mString->clear();
01015   const int UTF8_1BYTE = 128;
01016   const int UTF8_2BYTE = 128+64;
01017   const int UTF8_3BYTE = 128+64+32;
01018   const int UTF8_4BYTE = 128+64+32+16;
01019 
01020   for( int i=start; i<byte_count; ++i )
01021   {
01022     // Unicode            Byte1     Byte2     Byte3     Byte4
01023     // U+000000-U+00007F  0xxxxxxx
01024     // U+000080-U+0007FF  110xxxxx  10xxxxxx
01025     // U+000800-U+00FFFF  1110xxxx  10xxxxxx  10xxxxxx
01026     // U+010000-U+10FFFF  11110xxx  10xxxxxx  10xxxxxx  10xxxxxx
01027 
01028     unsigned int unicode_code_point = 0;
01029     if (utf8[i] < UTF8_1BYTE)
01030       unicode_code_point = utf8[i];
01031     else
01032     if ( (utf8[i] & UTF8_3BYTE) == UTF8_2BYTE )
01033     {
01034       unicode_code_point = ((utf8[i]-UTF8_2BYTE)<<6) + (utf8[i+1]&0x3f);
01035       i+=1;
01036     }
01037     else
01038     if ( (utf8[i] & UTF8_4BYTE) == UTF8_3BYTE )
01039     {
01040       unicode_code_point = ((utf8[i]-UTF8_3BYTE)<<12) + ((utf8[i+1]&0x3f)<<6) + (utf8[i+2]&0x3f);
01041       i+=2;
01042     }
01043     else
01044     {
01045       unicode_code_point = ((utf8[i]-UTF8_4BYTE)<<18) + ((utf8[i+1]&0x3f)<<12) + ((utf8[i+2]&0x3f)<<6) + (utf8[i+3]&0x3f);
01046       i+=3;
01047     }
01048 
01049     if (unicode_code_point <= 0xFFFF)
01050       s.mString->push_back((wchar_t)unicode_code_point);
01051     else // characters outside the BMP
01052       s.mString->push_back(L'?');
01053   }
01054   return s;
01055 }
01056 //-----------------------------------------------------------------------------
01057 String String::fromLatin1(const char* str, int character_count)
01058 {
01059   String s;
01060   s.acquireData();
01061 
01062   unsigned char* latin1 = (unsigned char*)str;
01063   if (character_count<0)
01064     for(character_count=0; latin1[character_count]; ) ++character_count;
01065 
01066   s.mString->clear();
01067   for(int i=0; i<character_count; ++i)
01068     s.mString->push_back( latin1_to_unicode[ latin1[i] ] );
01069   return s;
01070 }
01071 //-----------------------------------------------------------------------------
01072 String String::fromPointer(const void* value)
01073 {
01074   char buffer[32];
01075   memset(buffer, 0, sizeof(buffer));
01076   sprintf(buffer, "%p", value);
01077   return fromAscii(buffer);
01078 }
01079 //-----------------------------------------------------------------------------
01080 String String::fromInt(int value)
01081 {
01082   char buffer[256];
01083   memset(buffer, 0, sizeof(buffer));
01084   sprintf(buffer, "%d", value);
01085   return fromAscii(buffer);
01086 }
01087 //-----------------------------------------------------------------------------
01088 String String::fromUInt(unsigned int value)
01089 {
01090   char buffer[256];
01091   memset(buffer, 0, sizeof(buffer));
01092   sprintf(buffer, "%u", value);
01093   return fromAscii(buffer);
01094 }
01095 //-----------------------------------------------------------------------------
01096 String String::fromLongLong(long long value)
01097 {
01098   char buffer[256];
01099   memset(buffer, 0, sizeof(buffer));
01100   sprintf(buffer, "%lld", value);
01101   return fromAscii(buffer);
01102 }
01103 //-----------------------------------------------------------------------------
01104 String String::fromULongLong(unsigned long long value)
01105 {
01106   char buffer[256];
01107   memset(buffer, 0, sizeof(buffer));
01108   sprintf(buffer, "%llu", value);
01109   return fromAscii(buffer);
01110 }
01111 //-----------------------------------------------------------------------------
01112 String String::fromDouble(double value, int decimals)
01113 {
01114   char buffer[256];
01115   memset(buffer, 0, sizeof(buffer));
01116   switch(decimals)
01117   {
01118     case 0: sprintf(buffer, "%.0lf", value); break;
01119     case 1: sprintf(buffer, "%.1lf", value); break;
01120     case 2: sprintf(buffer, "%.2lf", value); break;
01121     case 3: sprintf(buffer, "%.3lf", value); break;
01122     case 4: sprintf(buffer, "%.4lf", value); break;
01123     case 5: sprintf(buffer, "%.5lf", value); break;
01124     case 6: sprintf(buffer, "%.6lf", value); break;
01125     case 7: sprintf(buffer, "%.7lf", value); break;
01126     case 8: sprintf(buffer, "%.8lf", value); break;
01127     case 9: sprintf(buffer, "%.9lf", value); break;
01128     case 10: sprintf(buffer, "%.10lf", value); break;
01129     case 11: sprintf(buffer, "%.11lf", value); break;
01130     case 12: sprintf(buffer, "%.12lf", value); break;
01131     case 13: sprintf(buffer, "%.13lf", value); break;
01132     case 14: sprintf(buffer, "%.14lf", value); break;
01133     case 15: sprintf(buffer, "%.15lf", value); break;
01134     case 16: sprintf(buffer, "%.16lf", value); break;
01135     case 17: sprintf(buffer, "%.17lf", value); break;
01136     case 18: sprintf(buffer, "%.18lf", value); break;
01137     case 19: sprintf(buffer, "%.19lf", value); break;
01138     case 20: sprintf(buffer, "%.20lf", value); break;
01139     default: sprintf(buffer, "%.6lf", value); break;
01140   }
01141   return fromAscii(buffer);
01142 }
01143 //-----------------------------------------------------------------------------
01144 std::wstring String::toStdWString() const
01145 {
01146   //createData();
01147   if (empty())
01148     return std::wstring();
01149 
01150   std::wstring ws;
01151   for(int i=0; i<length(); ++i)
01152     ws += (*mString)[i];
01153   return ws;
01154 }
01155 //-----------------------------------------------------------------------------
01156 std::string String::toStdString() const
01157 {
01158   //createData();
01159   if (empty())
01160     return std::string();
01161   std::string std_string;
01162 
01163   std::vector<unsigned char> utf8;
01164   toUTF8(utf8, false);
01165   if (utf8.size()>1)
01166   {
01167     std_string.resize(utf8.size()-1);
01168     memcpy(&std_string[0], &utf8[0], utf8.size()-1);
01169   }
01170 
01171   return std_string;
01172 }
01173 //-----------------------------------------------------------------------------
01174 void String::toAscii(std::string& ascii, bool translate_non_ascii_chars) const
01175 {
01176   //createData();
01177   if (empty())
01178   {
01179     ascii.clear();
01180     return;
01181   }
01182 
01183   ascii.clear();
01184   if (mString->length())
01185   {
01186     for(int i=0; i<(int)mString->length() && (*mString)[i]; ++i)
01187     {
01188       if ( (*mString)[i] < 128 || !translate_non_ascii_chars )
01189         ascii += (char)((*mString)[i] & 0xFF);
01190       else
01191       {
01192         const char* translation = unicode_to_ascii( (*mString)[i] );
01193         if (translation)
01194         {
01195           for(int j=0; translation[j]; ++j)
01196             ascii += translation[j];
01197         }
01198         else
01199           ascii += '?';
01200       }
01201     }
01202   }
01203   // no need to add the 0 terminator
01204 }
01205 //-----------------------------------------------------------------------------
01206 void String::toUTF8(std::string& str, bool include_utf8_signature) const
01207 {
01208   std::vector<unsigned char> utf8;
01209   toUTF8(utf8, include_utf8_signature);
01210   str.clear();
01211   if (utf8.size())
01212   {
01213     for(int i=0; utf8[i]; ++i)
01214       str.push_back(utf8[i]);
01215   }
01216 }
01217 //-----------------------------------------------------------------------------
01218 void String::toUTF8(std::vector<unsigned char>& utf8, bool include_utf8_signature) const
01219 {
01220   utf8.clear();
01221   if(include_utf8_signature)
01222   {
01223     utf8.push_back(0xEF);
01224     utf8.push_back(0xBB);
01225     utf8.push_back(0xBF);
01226   }
01227 
01228   //createData();
01229   if (empty())
01230   {
01231     utf8.push_back(0);
01232     return;
01233   }
01234 
01235   // Unicode            Byte1     Byte2     Byte3     Byte4
01236   // U+000000-U+00007F  0xxxxxxx
01237   // U+000080-U+0007FF  110xxxxx  10xxxxxx
01238   // U+000800-U+00FFFF  1110xxxx  10xxxxxx  10xxxxxx
01239   // U+010000-U+10FFFF  11110xxx  10xxxxxx  10xxxxxx  10xxxxxx
01240   for(int i=0; i<length(); ++i)
01241   {
01242     if ( (*mString)[i] < 0x80)
01243       utf8.push_back( (unsigned char)(*mString)[i] );
01244     else
01245     if ( (*mString)[i] < 0x800)
01246     {
01247       int a = 0xC0 | ((*mString)[i]>>6);
01248       int b = 0x80 | ((*mString)[i]&0x3F);
01249       utf8.push_back( (unsigned char)a );
01250       utf8.push_back( (unsigned char)b );
01251     }
01252     else
01253     {
01254       int a = 0xE0 | ((*mString)[i]>>12);
01255       int b = 0x80 | (((*mString)[i]>>6)&0x3F);
01256       int c = 0x80 | ((*mString)[i]&0x3F);
01257       utf8.push_back( (unsigned char)a );
01258       utf8.push_back( (unsigned char)b );
01259       utf8.push_back( (unsigned char)c );
01260     }
01261   }
01262 
01263   utf8.push_back(0);
01264 }
01265 //-----------------------------------------------------------------------------
01266 void String::toUTF16BE(std::vector<unsigned char>& utf16, bool include_utf16be_signature) const
01267 {
01268   utf16.clear();
01269   if (include_utf16be_signature)
01270   {
01271     utf16.push_back(0xFE);
01272     utf16.push_back(0xFF);
01273   }
01274 
01275   //createData();
01276   if (empty())
01277   {
01278     utf16.push_back(0);
01279     return;
01280   }
01281 
01282   for(int i=0; i<length(); ++i)
01283   {
01284     int x = ((*mString)[i]>>8) & 0xFF;
01285     int y = (*mString)[i]      & 0xFF;
01286     utf16.push_back( (unsigned char)x );
01287     utf16.push_back( (unsigned char)y );
01288   }
01289   utf16.push_back(0);
01290 }
01291 //-----------------------------------------------------------------------------
01292 void String::toUTF16LE(std::vector<unsigned char>& utf16, bool include_utf16le_signature) const
01293 {
01294   utf16.clear();
01295   if (include_utf16le_signature)
01296   {
01297     utf16.push_back(0xFF);
01298     utf16.push_back(0xFE);
01299   }
01300 
01301   //createData();
01302   if (empty())
01303   {
01304     utf16.push_back(0);
01305     return;
01306   }
01307 
01308   for(int i=0; i<length(); ++i)
01309   {
01310     int x = (*mString)[i] & 0xFF;
01311     int y = ((*mString)[i]>>8) & 0xFF;
01312     utf16.push_back( (unsigned char)x );
01313     utf16.push_back( (unsigned char)y );
01314   }
01315   utf16.push_back(0);
01316 }
01317 //-----------------------------------------------------------------------------
01318 void String::toLatin1(std::vector<unsigned char>& latin1) const
01319 {
01320   latin1.clear();
01321 
01322   //createData();
01323   if (empty())
01324   {
01325     latin1.push_back(0);
01326     return;
01327   }
01328 
01329   for(int i=0; i<length(); ++i)
01330   {
01331     if ((*mString)[i] < 128)
01332       latin1.push_back((unsigned char)(*mString)[i]);
01333     else
01334     {
01335       // search candidate
01336       int j=128;
01337       for(; latin1_to_unicode[j]; ++j)
01338       {
01339         if ( latin1_to_unicode[j] == (*mString)[i] )
01340         {
01341           latin1.push_back((unsigned char)j);
01342           break;
01343         }
01344       }
01345       if (j==256)
01346         latin1.push_back('?');
01347     }
01348   }
01349   latin1.push_back(0);
01350 }
01351 //-----------------------------------------------------------------------------
01352 int String::toInt(bool hex) const
01353 {
01354   //createData();
01355   if (empty())
01356     return 0;
01357 
01358   if (hex)
01359   {
01360     int i=0;
01361     sscanf(toStdString().c_str(), "%x", &i);
01362     return i;
01363   }
01364   else
01365     return atoi( toStdString().c_str() );
01366 }
01367 //-----------------------------------------------------------------------------
01368 double String::toDouble() const
01369 {
01370   //createData();
01371   if (empty())
01372     return 0.0;
01373 
01374   return atof( toStdString().c_str() );
01375 }
01376 //-----------------------------------------------------------------------------
01377 void String::filterStrings(std::vector<String>& strings, const String& filter)
01378 {
01379   String match = filter;
01380   int filter_type = 0;
01381   bool filter_ok = filter.empty();
01382 
01383   if ( filter.startsWith('*') )
01384   {
01385     filter_type--; // -1
01386     match.remove(0, 1);
01387     filter_ok = true;
01388   }
01389 
01390   if ( filter.endsWith('*') )
01391   {
01392     filter_type++; // +1 or 0
01393     match.remove(match.length()-1, 1);
01394     filter_ok = true;
01395   }
01396 
01397   if ( !filter_ok )
01398   {
01399     Log::error( Say("unacceptable filter '%s'.\n") << filter );
01400     return;
01401   }
01402 
01403   if ( filter_type && filter.length() > 1 )
01404   {
01405     for( int i=(int)strings.size(); i--; )
01406       switch(filter_type)
01407       {
01408         case 0:  if(  strings[i].find(match) == -1 ) strings.erase( strings.begin() + i ); break;
01409         case -1: if( !strings[i].endsWith(match)   ) strings.erase( strings.begin() + i ); break;
01410         case +1: if( !strings[i].startsWith(match) ) strings.erase( strings.begin() + i ); break;
01411       }
01412   }
01413 }
01414 //-----------------------------------------------------------------------------
01415 EStringEncoding String::detectEncoding(const void* str, int byte_count, EStringEncoding default_encoding)
01416 {
01417   const unsigned char* h = (unsigned char*)str;
01418   // UTF32 LE -> FF FE 00 00
01419   // UTF32 BE -> 00 00 FE FF
01420   // UTF8     -> EF BB BF
01421   // UTF16 BE -> FE FF
01422   // UTF16 LE -> FF FE
01423 
01424   if (byte_count>4 && h[0] == 0xFF && h[1] == 0xFE && h[2] == 0    && h[3] == 0   ) return SE_UTF32_LE;
01425   if (byte_count>4 && h[0] == 0    && h[1] == 0    && h[2] == 0xFE && h[3] == 0xFF) return SE_UTF32_BE;
01426   if (byte_count>3 && h[0] == 0xEF && h[1] == 0xBB && h[2] == 0xBF                ) return SE_UTF8;
01427   if (byte_count>2 && h[0] == 0xFE && h[1] == 0xFF                                ) return SE_UTF16_BE;
01428   if (byte_count>2 && h[0] == 0xFF && h[1] == 0xFE                                ) return SE_UTF16_LE;
01429   return default_encoding;
01430 }
01431 //-----------------------------------------------------------------------------
01432 unsigned short String::getUpperCase(unsigned short ch)
01433 {
01434   for(int i=0; i<107; ++i)
01435   {
01436     if (ch >= case_table_start_min_max[i][1] && ch <= case_table_start_min_max[i][2])
01437     {
01438       int index = ch - case_table_start_min_max[i][1] + case_table_start_min_max[i][0];
01439       return case_table_upper_lower_title[index][0];
01440     }
01441   }
01442   return ch;
01443 }
01444 //-----------------------------------------------------------------------------
01445 unsigned short String::getLowerCase(unsigned short ch)
01446 {
01447   for(int i=0; i<107; ++i)
01448   {
01449     if (ch >= case_table_start_min_max[i][1] && ch <= case_table_start_min_max[i][2])
01450     {
01451       int index = ch - case_table_start_min_max[i][1] + case_table_start_min_max[i][0];
01452       return case_table_upper_lower_title[index][1];
01453     }
01454   }
01455   return ch;
01456 }
01457 //-----------------------------------------------------------------------------
01458 unsigned short String::getTitleCase(unsigned short ch)
01459 {
01460   for(int i=0; i<107; ++i)
01461   {
01462     if (ch >= case_table_start_min_max[i][1] && ch <= case_table_start_min_max[i][2])
01463     {
01464       int index = ch - case_table_start_min_max[i][1] + case_table_start_min_max[i][0];
01465       return case_table_upper_lower_title[index][2];
01466     }
01467   }
01468   return ch;
01469 }
01470 //-----------------------------------------------------------------------------
01471 std::string String::trimStdString(const std::string& text)
01472 {
01473   std::string trimmed;
01474   for(unsigned i=0; i<text.length(); ++i)
01475   {
01476     if(text[i] == ' '  ||
01477        text[i] == '\n' ||
01478        text[i] == '\t' ||
01479        text[i] == '\v' ||
01480        text[i] == '\b' ||
01481        text[i] == '\a' ||
01482        text[i] == '\f' ||
01483        text[i] == '\r' )
01484       continue;
01485     else
01486     {
01487       trimmed = text.c_str() + i;
01488       break;
01489     }
01490   }
01491   int i = (int)trimmed.length();
01492   while( i-- )
01493   {
01494     if(trimmed[i] == ' '  ||
01495        trimmed[i] == '\n' ||
01496        trimmed[i] == '\t' ||
01497        trimmed[i] == '\v' ||
01498        trimmed[i] == '\b' ||
01499        trimmed[i] == '\a' ||
01500        trimmed[i] == '\f' ||
01501        trimmed[i] == '\r' )
01502       continue;
01503     else
01504       break;
01505   }
01506   trimmed.resize( i+1 );
01507   return trimmed;
01508 }
01509 //-----------------------------------------------------------------------------
01510 String String::printf(const char* fmt, ...)
01511 {
01512   std::vector<char> buffer;
01513   buffer.resize(1024 + strlen(fmt));
01514   buffer[0] = 0;
01515 
01516   va_list ap;
01517   va_start(ap, fmt);
01518   vsnprintf(&buffer[0], buffer.size(), fmt, ap);
01519   va_end(ap);
01520   return &buffer[0];
01521 }
01522 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:31.
Permission is granted to use this page to write and publish articles regarding Visualization Library.