newspeoplefor developersdocumentationdownloads

nstring.h

Go to the documentation of this file.
00001 #ifndef N_STRING_H
00002 #define N_STRING_H
00003 //------------------------------------------------------------------------------
00019 #include <ctype.h>
00020 #include <string.h>
00021 #include <stdarg.h>
00022 #ifdef __WIN32__
00023 #include <malloc.h>
00024 #else
00025 #include <alloca.h>
00026 #endif
00027 
00028 #include "kernel/ntypes.h"
00029 #include "util/narray.h"
00030 #include "mathlib/vector.h"
00031 #include "mathlib/matrix.h"
00032 
00033 //------------------------------------------------------------------------------
00034 class nString
00035 {
00036 public:
00038     nString();
00040     nString(const char* str);
00042     nString(const nString& rhs);
00044     ~nString();
00046     nString& operator=(const nString& rhs);
00048     nString& operator=(const char* rhs);
00050     nString& operator+=(const char* rhs);
00052     nString& operator+=(const nString& rhs);
00054     friend bool operator == (const nString& a, const nString& b);
00056     friend bool operator != (const nString& a, const nString& b);
00058     friend bool operator < (const nString& a, const nString& b);
00060     friend bool operator > (const nString& a, const nString& b);
00062     friend bool operator <= (const nString& a, const nString& b);
00064     friend bool operator >= (const nString& a, const nString& b);
00066     char operator[](int i) const;
00068     char& operator[](int i);
00070     void Set(const char* ptr, int length);
00072     void Set(const char* str);
00074     void SetInt(int val);
00076     void SetFloat(float val);
00078     void SetBool(bool val);
00080     void SetVector3(const vector3& v);
00082     void SetVector4(const vector4& v);
00084     void SetMatrix44(const matrix44& m);
00086     const char* Get() const;
00088     int AsInt() const;
00090     float AsFloat() const;
00092     bool AsBool() const;
00094     vector3 AsVector3() const;
00096     vector4 AsVector4() const;
00098     matrix44 AsMatrix44() const;
00100     bool IsValidInt() const;
00102     bool IsValidFloat() const;
00104     bool IsValidBool() const;
00106     bool IsValidVector3() const;
00108     bool IsValidVector4() const;
00110     bool IsValidMatrix44() const;
00112     int Length() const;
00114     void Clear();
00116     bool IsEmpty() const;
00118     bool IsValid() const;
00120     void Append(const char* str);
00122     void Append(const nString& str);
00124     void AppendRange(const char* str, uint numChars);
00126     void AppendInt(int val);
00128     void AppendFloat(float val);
00130     void ToLower();
00132     void ToUpper();
00134     const char* GetFirstToken(const char* whiteSpace);
00136     const char* GetNextToken(const char* whiteSpace);
00138     int Tokenize(const char* whiteSpace, nArray<nString>& tokens) const;
00140     int Tokenize(const char* whiteSpace, uchar fence, nArray<nString>& tokens) const;
00142     nString ExtractRange(int from, int numChars) const;
00144     void Strip(const char* charSet);
00146     int FindStringIndex(const nString& v, int startIndex) const;
00148     int FindCharIndex(unsigned char c, int startIndex) const;
00150     void TerminateAtIndex(int index);
00152     bool ContainsCharFromSet(const char* charSet) const;
00154     void StripTrailingSlash();
00156     nString TrimLeft(const char* charSet) const;
00158     nString TrimRight(const char* charSet) const;
00160     nString Trim(const char* charSet) const;
00162     nString Substitute(const char* str, const char* substStr) const;
00164     void SubstituteCharacter(char c, char subst);
00166     void UTF8toANSI();
00168     void ANSItoUTF8();
00170     const char* GetExtension() const;
00172     bool CheckExtension(const char* ext) const;
00174     void ConvertBackslashes();
00176     void StripExtension();
00178     nString ExtractFileName() const;
00180     nString ExtractLastDirName() const;
00182     nString ExtractDirName() const;
00184     nString ExtractToLastSlash() const;
00186     bool MatchPattern(const nString& pattern) const;
00188     void __cdecl Format(const char* fmtString, ...)
00189             __attribute__((format(printf,2,3)));
00191     void FormatWithArgs(const char* fmtString, va_list args);
00193     void ReplaceIllegalFilenameChars(char replacement);
00195     bool CheckValidCharSet(const nString& charSet) const;
00197     void ReplaceChars(const char* charSet, char replacement);
00199     static nString Concatenate(const nArray<nString>& strArray, const nString& whiteSpace);
00201     static nString FromInt(int i);
00203     static nString FromFloat(float f);
00205     static nString FromBool(bool b);
00207     static nString FromVector3(const vector3& v);
00209     static nString FromVector4(const vector4& v);
00211     static nString FromMatrix44(const matrix44& m);
00212 
00213 protected:
00215     void Copy(const nString& src);
00217     void Delete();
00219     char* GetLastSlash() const;
00221     size_t GetFormattedStringLength(const char* format, va_list argList) const;
00223     void SetLength(int);
00224 
00225     enum
00226     {
00227         LOCALSTRINGSIZE = 14,
00228     };
00229     char* string;
00230     union
00231     {
00232         struct
00233         {
00234             char localString[LOCALSTRINGSIZE];
00235             ushort localStrLen;
00236         };
00237         uint strLen;
00238     };
00239 };
00240 
00241 //------------------------------------------------------------------------------
00244 inline
00245 nString::nString() :
00246     string(0),
00247     strLen(0),
00248     localStrLen(0)
00249 {
00250 }
00251 
00252 //------------------------------------------------------------------------------
00255 inline
00256 void
00257 nString::Delete()
00258 {
00259     if (this->string)
00260     {
00261         n_free((void*) this->string);
00262         this->string = 0;
00263     }
00264     this->localString[0] = 0;
00265     this->localStrLen = 0;
00266 }
00267 
00268 //------------------------------------------------------------------------------
00271 inline
00272 nString::~nString()
00273 {
00274     this->Delete();
00275 }
00276 
00277 //------------------------------------------------------------------------------
00280 inline
00281 void
00282 nString::Set(const char* str, int length)
00283 {
00284     this->Delete();
00285     if (str)
00286     {
00287         if (length >= LOCALSTRINGSIZE)
00288         {
00289             this->string = (char*)n_malloc(length + 1);
00290             memcpy(this->string, str, length);
00291             this->string[length] = 0;
00292             this->strLen = length;
00293         }
00294         else
00295         {
00296             memcpy(this->localString, str, length);
00297             this->localString[length] = 0;
00298             this->localStrLen = (ushort)length;
00299         }
00300     }
00301 }
00302 
00303 //------------------------------------------------------------------------------
00306 inline
00307 void
00308 nString::Set(const char* str)
00309 {
00310     int len = 0;
00311     if (str)
00312     {
00313         len = (int) strlen(str);
00314     }
00315     this->Set(str, len);
00316 }
00317 
00318 //------------------------------------------------------------------------------
00321 inline
00322 void
00323 nString::SetInt(int val)
00324 {
00325     this->Format("%d", val);
00326 }
00327 
00328 //------------------------------------------------------------------------------
00331 inline
00332 void
00333 nString::SetFloat(float val)
00334 {
00335     this->Format("%.6f", val);
00336 }
00337 
00338 //------------------------------------------------------------------------------
00341 inline
00342 void
00343 nString::SetBool(bool val)
00344 {
00345     if (val)
00346     {
00347         *this = "true";
00348     }
00349     else
00350     {
00351         *this = "false";
00352     }
00353 }
00354 
00355 //------------------------------------------------------------------------------
00358 inline
00359 void
00360 nString::SetVector3(const vector3& v)
00361 {
00362     this->Format("%.6f,%.6f,%.6f", v.x, v.y, v.z);
00363 }
00364 
00365 //------------------------------------------------------------------------------
00368 inline
00369 void
00370 nString::SetVector4(const vector4& v)
00371 {
00372     this->Format("%.6f,%.6f,%.6f,%.6f", v.x, v.y, v.z, v.w);
00373 }
00374 
00375 //------------------------------------------------------------------------------
00378 inline
00379 void
00380 nString::SetMatrix44(const matrix44& m)
00381 {
00382     this->Format("%.6f, %.6f, %.6f, %.6f, "
00383         "%.6f, %.6f, %.6f, %.6f, "
00384         "%.6f, %.6f, %.6f, %.6f, "
00385         "%.6f, %.6f, %.6f, %.6f",
00386         m.M11, m.M12, m.M13, m.M14,
00387         m.M21, m.M22, m.M23, m.M24,
00388         m.M31, m.M32, m.M33, m.M34,
00389         m.M41, m.M42, m.M43, m.M44);
00390 }
00391 
00392 //------------------------------------------------------------------------------
00395 inline
00396 void
00397 nString::Copy(const nString& src)
00398 {
00399     n_assert(0 == this->string);
00400     const char* str = src.Get();
00401     if (str)
00402     {
00403         this->Set(str);
00404     }
00405 }
00406 
00407 //------------------------------------------------------------------------------
00410 inline
00411 nString::nString(const char* str) :
00412     string(0),
00413     strLen(0),
00414     localStrLen(0)
00415 {
00416     this->Set(str);
00417 }
00418 
00419 //------------------------------------------------------------------------------
00422 inline
00423 nString::nString(const nString& rhs) :
00424     string(0),
00425     strLen(0)
00426 {
00427     this->localString[0] = 0;
00428     this->Copy(rhs);
00429 }
00430 
00431 //------------------------------------------------------------------------------
00434 inline
00435 const char*
00436 nString::Get() const
00437 {
00438     if (this->string)
00439     {
00440         return this->string;
00441     }
00442     if (this->localString[0])
00443     {
00444         return this->localString;
00445     }
00446     return "";
00447 }
00448 
00449 //------------------------------------------------------------------------------
00452 inline
00453 nString&
00454 nString::operator=(const nString& rhs)
00455 {
00456     if (&rhs != this)
00457     {
00458         this->Delete();
00459         this->Copy(rhs);
00460     }
00461     return *this;
00462 }
00463 
00464 //------------------------------------------------------------------------------
00467 inline
00468 nString&
00469 nString::operator=(const char* rhs)
00470 {
00471     if (rhs != this->Get())
00472     {
00473         this->Set(rhs);
00474     }
00475     return *this;
00476 }
00477 
00478 //------------------------------------------------------------------------------
00481 inline
00482 void
00483 nString::AppendRange(const char* str, uint numChars)
00484 {
00485     n_assert(str);
00486     if (numChars > 0)
00487     {
00488         uint rlen = numChars;
00489         uint tlen = this->Length() + rlen;
00490         if (this->string)
00491         {
00492             char* ptr = (char*)n_malloc(tlen + 1);
00493             strcpy(ptr, this->string);
00494             strncat(ptr, str, numChars);
00495             n_free((void*)this->string);
00496             this->string = ptr;
00497             this->strLen = tlen;
00498         }
00499         else if (this->localString[0])
00500         {
00501             if (tlen >= LOCALSTRINGSIZE)
00502             {
00503                 char* ptr = (char*)n_malloc(tlen + 1);
00504                 strcpy(ptr, this->localString);
00505                 strncat(ptr, str, numChars);
00506                 this->localString[0] = 0;
00507                 this->string = ptr;
00508                 this->strLen = tlen;
00509             }
00510             else
00511             {
00512                 strncat(this->localString, str, numChars);
00513                 this->localStrLen = (ushort)tlen;
00514             }
00515         }
00516         else
00517         {
00518             this->Set(str, numChars);
00519         }
00520     }
00521 }
00522 
00523 //------------------------------------------------------------------------------
00526 inline
00527 void
00528 nString::Append(const char* str)
00529 {
00530     n_assert(str);
00531     uint rlen = strlen(str);
00532     this->AppendRange(str, rlen);
00533 }
00534 
00535 //------------------------------------------------------------------------------
00538 inline
00539 void
00540 nString::Append(const nString& str)
00541 {
00542     this->Append(str.Get());
00543 }
00544 
00545 //------------------------------------------------------------------------------
00548 inline
00549 void
00550 nString::AppendInt(int val)
00551 {
00552     nString str;
00553     str.SetInt(val);
00554     this->Append(str);
00555 }
00556 
00557 //------------------------------------------------------------------------------
00560 inline
00561 void
00562 nString::AppendFloat(float val)
00563 {
00564     nString str;
00565     str.SetFloat(val);
00566     this->Append(str);
00567 }
00568 
00569 //------------------------------------------------------------------------------
00572 inline
00573 nString&
00574 nString::operator+=(const char* rhs)
00575 {
00576     this->Append(rhs);
00577     return *this;
00578 }
00579 
00580 //------------------------------------------------------------------------------
00583 inline
00584 nString&
00585 nString::operator+=(const nString& rhs)
00586 {
00587     this->Append(rhs.Get());
00588     return *this;
00589 }
00590 
00591 //------------------------------------------------------------------------------
00594 inline
00595 bool
00596 operator == (const nString& a, const nString& b)
00597 {
00598     return strcmp(a.Get(), b.Get()) == 0;
00599 }
00600 
00601 //------------------------------------------------------------------------------
00604 inline
00605 bool
00606 operator != (const nString& a, const nString& b)
00607 {
00608     return strcmp(a.Get(), b.Get()) != 0;
00609 }
00610 
00611 //------------------------------------------------------------------------------
00614 inline
00615 bool
00616 operator < (const nString& a, const nString& b)
00617 {
00618     return strcmp(a.Get(), b.Get()) < 0;
00619 }
00620 
00621 //------------------------------------------------------------------------------
00624 inline
00625 bool
00626 operator > (const nString& a, const nString& b)
00627 {
00628     return strcmp(a.Get(), b.Get()) > 0;
00629 }
00630 
00631 //------------------------------------------------------------------------------
00634 inline
00635 bool
00636 operator <= (const nString& a, const nString& b)
00637 {
00638     return strcmp(a.Get(), b.Get()) <= 0;
00639 }
00640 
00641 //------------------------------------------------------------------------------
00644 inline
00645 bool
00646 operator >= (const nString& a, const nString& b)
00647 {
00648     return strcmp(a.Get(), b.Get()) >= 0;
00649 }
00650 
00651 //------------------------------------------------------------------------------
00655 inline
00656 char
00657 nString::operator[](int i) const
00658 {
00659     n_assert((0 <= i) && (i <= this->Length()));
00660     if (this->string != 0)
00661     {
00662         return this->string[i];
00663     }
00664     return this->localString[i];
00665 }
00666 
00667 //------------------------------------------------------------------------------
00671 inline
00672 char&
00673 nString::operator[](int i)
00674 {
00675     n_assert((0 <= i) && (i <= this->Length()));
00676     if (this->string != 0)
00677     {
00678         return this->string[i];
00679     }
00680     else
00681     {
00682         return this->localString[i];
00683     }
00684 }
00685 
00686 //------------------------------------------------------------------------------
00689 inline
00690 int
00691 nString::Length() const
00692 {
00693     if (this->string != 0)
00694     {
00695         return this->strLen;
00696     }
00697     return this->localStrLen;
00698 }
00699 
00700 //------------------------------------------------------------------------------
00703 inline
00704 void
00705 nString::Clear()
00706 {
00707     this->Delete();
00708 }
00709 
00710 //------------------------------------------------------------------------------
00713 inline
00714 bool
00715 nString::IsEmpty() const
00716 {
00717     if (this->string && (this->string[0] != 0))
00718     {
00719         return false;
00720     }
00721     if (this->localString[0] != 0)
00722     {
00723         return false;
00724     }
00725     return true;
00726 }
00727 
00728 //------------------------------------------------------------------------------
00731 inline
00732 bool
00733 nString::IsValid() const
00734 {
00735     return !this->IsEmpty();
00736 }
00737 
00738 //------------------------------------------------------------------------------
00741 inline
00742 void
00743 nString::ToLower()
00744 {
00745     char* str = (char*)(this->string ? this->string : this->localString);
00746     if (str)
00747     {
00748         char c;
00749         char* ptr = (char*)str;
00750         while ((c = *ptr))
00751         {
00752             *ptr++ = tolower(c);
00753         }
00754     }
00755 }
00756 
00757 //------------------------------------------------------------------------------
00760 inline
00761 void
00762 nString::ToUpper()
00763 {
00764     char* str = (char*)(this->string ? this->string : this->localString);
00765     if (str)
00766     {
00767         char c;
00768         char* ptr = (char*)str;
00769         while ((c = *ptr))
00770         {
00771             *ptr++ = toupper(c);
00772         }
00773     }
00774 }
00775 
00776 //------------------------------------------------------------------------------
00779 static
00780 inline
00781 nString
00782 operator+(const nString& s0, const nString& s1)
00783 {
00784     nString newString = s0;
00785     newString.Append(s1.Get());
00786     return newString;
00787 }
00788 
00789 //------------------------------------------------------------------------------
00802 inline
00803 const char*
00804 nString::GetFirstToken(const char* whiteSpace)
00805 {
00806     n_assert(whiteSpace);
00807     return strtok((char*)this->Get(), whiteSpace);
00808 }
00809 
00810 //------------------------------------------------------------------------------
00822 inline
00823 const char*
00824 nString::GetNextToken(const char* whiteSpace)
00825 {
00826     n_assert(whiteSpace);
00827     return strtok(0, whiteSpace);
00828 }
00829 
00830 //------------------------------------------------------------------------------
00841 inline
00842 int
00843 nString::Tokenize(const char* whiteSpace, nArray<nString>& tokens) const
00844 {
00845     int numTokens = 0;
00846 
00847     // create a temporary string, which will be destroyed during the operation
00848     nString str(*this);
00849     char* ptr = (char*)str.Get();
00850     const char* token;
00851     while (0 != (token = strtok(ptr, whiteSpace)))
00852     {
00853         tokens.Append(token);
00854         ptr = 0;
00855         numTokens++;
00856     }
00857     return numTokens;
00858 }
00859 
00860 //------------------------------------------------------------------------------
00873 inline
00874 int
00875 nString::Tokenize(const char* whiteSpace, uchar fence, nArray<nString>& tokens) const
00876 {
00877     // create a temporary string, which will be destroyed during the operation
00878     nString str(*this);
00879     char* ptr = (char*)str.Get();
00880     char* end = ptr + strlen(ptr);
00881     while (ptr < end)
00882     {
00883         char* c;
00884 
00885         // skip white space
00886         while (*ptr && strchr(whiteSpace, *ptr))
00887         {
00888             ptr++;
00889         }
00890         if (*ptr)
00891         {
00892             // check for fenced area
00893             if ((fence == *ptr) && (c = strchr(++ptr, fence)))
00894             {
00895                 *c++ = 0;
00896                 tokens.Append(ptr);
00897                 ptr = c;
00898             }
00899             else if ((c = strpbrk(ptr, whiteSpace)))
00900             {
00901                 *c++ = 0;
00902                 tokens.Append(ptr);
00903                 ptr = c;
00904             }
00905             else
00906             {
00907                 tokens.Append(ptr);
00908                 break;
00909             }
00910         }
00911     }
00912     return tokens.Size();
00913 }
00914 
00915 //------------------------------------------------------------------------------
00919 inline
00920 nString
00921 nString::ExtractRange(int from, int numChars) const
00922 {
00923     n_assert(from <= this->Length());
00924     n_assert((from + numChars) <= this->Length());
00925     const char* str = this->Get();
00926     nString newString;
00927     newString.Set(&(str[from]), numChars);
00928     return newString;
00929 }
00930 
00931 //------------------------------------------------------------------------------
00936 inline
00937 void
00938 nString::Strip(const char* charSet)
00939 {
00940     n_assert(charSet);
00941     char* str = (char*)this->Get();
00942     char* ptr = strpbrk(str, charSet);
00943     if (ptr)
00944     {
00945         *ptr = 0;
00946     }
00947     this->SetLength(strlen(str));
00948 
00949 }
00950 
00951 //------------------------------------------------------------------------------
00955 inline
00956 bool
00957 nString::ContainsCharFromSet(const char* charSet) const
00958 {
00959     n_assert(charSet);
00960     char* str = (char*)this->Get();
00961     char* ptr = strpbrk(str, charSet);
00962     return (0 != ptr);
00963 }
00964 
00965 //------------------------------------------------------------------------------
00969 inline
00970 int
00971 nString::FindStringIndex(const nString& v, int startIndex) const
00972 {
00973     n_assert(0 <= startIndex && startIndex <= Length() - 1);
00974     n_assert(!v.IsEmpty());
00975 
00976     for (int i = startIndex; i < Length(); i++)
00977     {
00978         if (Length() - i < v.Length())
00979         {
00980             break;
00981         }
00982 
00983         if (strncmp(&(Get()[i]), v.Get(), v.Length()) == 0)
00984         {
00985             return i;
00986         }
00987     }
00988 
00989     return -1;
00990 }
00991 
00992 //------------------------------------------------------------------------------
00996 inline
00997 int
00998 nString::FindCharIndex(unsigned char c, int startIndex) const
00999 {
01000     if (this->Length() > 0)
01001     {
01002         n_assert(startIndex < this->Length());
01003         const char* ptr = strchr(this->Get() + startIndex, c);
01004         if (ptr)
01005         {
01006             return ptr - this->Get();
01007         }
01008     }
01009     return -1;
01010 }
01011 
01012 //------------------------------------------------------------------------------
01016 inline
01017 void
01018 nString::TerminateAtIndex(int index)
01019 {
01020     n_assert(index < this->Length());
01021     char* ptr = (char*)this->Get();
01022     ptr[index] = 0;
01023     this->SetLength(strlen(this->Get()));
01024 }
01025 
01026 //------------------------------------------------------------------------------
01030 inline
01031 void
01032 nString::StripTrailingSlash()
01033 {
01034     if (this->Length() > 0)
01035     {
01036         int pos = Length() - 1;
01037         char* str = (char*)this->Get();
01038         if ((str[pos] == '/') || (str[pos] == '\\'))
01039         {
01040             str[pos] = 0;
01041             if (this->string != 0)
01042             {
01043                 this->strLen--;
01044             }
01045             else
01046             {
01047                 this->localStrLen--;
01048             }
01049         }
01050         this->SetLength(strlen(this->Get()));
01051     }
01052 }
01053 
01054 //------------------------------------------------------------------------------
01059 inline
01060 nString
01061 nString::TrimLeft(const char* charSet) const
01062 {
01063     n_assert(charSet);
01064     if (this->IsEmpty())
01065     {
01066         return *this;
01067     }
01068 
01069     int charSetLen = strlen(charSet);
01070     int thisIndex = 0;
01071     bool stopped = false;
01072     while (!stopped && (thisIndex < this->Length()))
01073     {
01074         int charSetIndex;
01075         bool match = false;
01076         for (charSetIndex = 0; charSetIndex < charSetLen; charSetIndex++)
01077         {
01078             if ((*this)[thisIndex] == charSet[charSetIndex])
01079             {
01080                 // a match
01081                 match = true;
01082                 break;
01083             }
01084         }
01085         if (!match)
01086         {
01087             // stop if no match
01088             stopped = true;
01089         }
01090         else
01091         {
01092             // a match, advance to next character
01093             ++thisIndex;
01094         }
01095     }
01096     nString trimmedString(&(this->Get()[thisIndex]));
01097     return trimmedString;
01098 }
01099 
01100 //------------------------------------------------------------------------------
01105 inline
01106 nString
01107 nString::TrimRight(const char* charSet) const
01108 {
01109     n_assert(charSet);
01110     if (this->IsEmpty())
01111     {
01112         return *this;
01113     }
01114 
01115     int charSetLen = strlen(charSet);
01116     int thisIndex = this->Length() - 1;
01117     bool stopped = false;
01118     while (!stopped && (thisIndex < this->Length()))
01119     {
01120         int charSetIndex;
01121         bool match = false;
01122         for (charSetIndex = 0; charSetIndex < charSetLen; charSetIndex++)
01123         {
01124             if ((*this)[thisIndex] == charSet[charSetIndex])
01125             {
01126                 // a match
01127                 match = true;
01128                 break;
01129             }
01130         }
01131         if (!match)
01132         {
01133             // stop if no match
01134             stopped = true;
01135         }
01136         else
01137         {
01138             // a match, advance to next character
01139             --thisIndex;
01140         }
01141     }
01142     nString trimmedString;
01143     trimmedString.Set(this->Get(), thisIndex + 1);
01144     return trimmedString;
01145 }
01146 
01147 //------------------------------------------------------------------------------
01151 inline
01152 nString
01153 nString::Trim(const char* charSet) const
01154 {
01155     return this->TrimLeft(charSet).TrimRight(charSet);
01156 }
01157 
01158 //------------------------------------------------------------------------------
01162 inline
01163 nString
01164 nString::Substitute(const char* matchStr, const char* substStr) const
01165 {
01166     n_assert(matchStr && substStr);
01167 
01168     const char* ptr = this->Get();
01169     int matchStrLen = strlen(matchStr);
01170     nString dest;
01171 
01172     // walk original string for occurrences of str
01173     const char* occur;
01174     while ((occur = strstr(ptr, matchStr)))
01175     {
01176         // append string fragment until match
01177         dest.AppendRange(ptr, occur - ptr);
01178 
01179         // append replacement string
01180         dest.Append(substStr);
01181 
01182         // adjust source pointer
01183         ptr = occur + matchStrLen;
01184     }
01185     dest.Append(ptr);
01186     return dest;
01187 }
01188 
01189 //------------------------------------------------------------------------------
01197 inline
01198 void
01199 nString::UTF8toANSI()
01200 {
01201     uchar* src = (uchar*)this->Get();
01202     uchar* dst = src;
01203     uchar c;
01204     while ((c = *src++))
01205     {
01206         if (c >= 0x80)
01207         {
01208             if ((c & 0xE0) == 0xC0)
01209             {
01210                 // a 2 byte sequence with 11 bits of information
01211                 ushort wide = ((c & 0x1F) << 6) | (*src++ & 0x3F);
01212                 if (wide > 0xff)
01213                 {
01214                     c = '?';
01215                 }
01216                 else
01217                 {
01218                     c = (uchar) wide;
01219                 }
01220             }
01221             else if ((c & 0xF0) == 0xE0)
01222             {
01223                 // a 3 byte sequence with 16 bits of information
01224                 c = '?';
01225                 src += 2;
01226             }
01227             else if ((c & 0xF8) == 0xF0)
01228             {
01229                 // a 4 byte sequence with 21 bits of information
01230                 c = '?';
01231                 src += 3;
01232             }
01233             else if ((c & 0xFC) == 0xF8)
01234             {
01235                 // a 5 byte sequence with 26 bits of information
01236                 c = '?';
01237                 src += 4;
01238             }
01239             else if ((c & 0xFE) == 0xFC)
01240             {
01241                 // a 6 byte sequence with 31 bits of information
01242                 c = '?';
01243                 src += 5;
01244             }
01245         }
01246         *dst++ = c;
01247     }
01248     *dst = 0;
01249 }
01250 
01251 //------------------------------------------------------------------------------
01255 inline
01256 void
01257 nString::ANSItoUTF8()
01258 {
01259     n_assert(!this->IsEmpty());
01260     int bufSize = this->Length() * 2 + 1;
01261     char* buffer = n_new_array(char, bufSize);
01262     char* dstPtr = buffer;
01263     const char* srcPtr = this->Get();
01264     unsigned char c;
01265     while ((c = *srcPtr++))
01266     {
01267         // note: this only covers the 2 cases that the character
01268         // is between 0 and 127 and between 128 and 255
01269         if (c < 128)
01270         {
01271             *dstPtr++ = c;
01272         }
01273         else
01274         {
01275             *dstPtr++ = 192 + (c / 64);
01276             *dstPtr++ = 128 + (c % 64);
01277         }
01278     }
01279     *dstPtr = 0;
01280     this->Set(buffer);
01281     n_delete_array(buffer);
01282 }
01283 
01284 //------------------------------------------------------------------------------
01288 inline
01289 void
01290 nString::SubstituteCharacter(char c, char subst)
01291 {
01292     char* ptr = (char*)this->Get();
01293     int i;
01294     for (i = 0; i <= this->Length(); i++)
01295     {
01296         if (ptr[i] == c)
01297         {
01298             ptr[i] = subst;
01299         }
01300     }
01301 }
01302 
01303 //------------------------------------------------------------------------------
01307 inline
01308 void
01309 nString::ConvertBackslashes()
01310 {
01311     this->SubstituteCharacter('\\', '/');
01312 }
01313 
01314 //------------------------------------------------------------------------------
01318 inline
01319 const char*
01320 nString::GetExtension() const
01321 {
01322     const char* str = this->Get();
01323     const char* ext = strrchr(str, '.');
01324     if (ext)
01325     {
01326         ext++;
01327         if (ext[0] != 0)
01328         {
01329             return ext;
01330         }
01331     }
01332     return 0;
01333 }
01334 
01335 //------------------------------------------------------------------------------
01342 inline
01343 bool
01344 nString::CheckExtension(const char* ext) const
01345 {
01346     n_assert(ext);
01347     const char* extStr = this->GetExtension();
01348     if (0 == extStr)
01349     {
01350         return false;
01351     }
01352     return (0 == (strcmp(ext, extStr)));
01353 }
01354 
01355 //------------------------------------------------------------------------------
01359 inline
01360 void
01361 nString::StripExtension()
01362 {
01363     char* ext = (char*)this->GetExtension();
01364     if (ext)
01365     {
01366         ext[-1] = 0;
01367     }
01368     this->SetLength(strlen(this->Get()));
01369 }
01370 
01371 //------------------------------------------------------------------------------
01375 inline
01376 char*
01377 nString::GetLastSlash() const
01378 {
01379     char* s = (char*)this->Get();
01380     char* lastSlash = strrchr(s, '/');
01381     if (0 == lastSlash) lastSlash = strrchr(s, '\\');
01382     if (0 == lastSlash) lastSlash = strrchr(s, ':');
01383     return lastSlash;
01384 }
01385 
01386 //------------------------------------------------------------------------------
01391 inline
01392 nString
01393 nString::ExtractFileName() const
01394 {
01395     nString pathString;
01396     char* lastSlash = this->GetLastSlash();
01397     if (lastSlash)
01398     {
01399         pathString = &(lastSlash[1]);
01400     }
01401     else
01402     {
01403         pathString = this->Get();
01404     }
01405     return pathString;
01406 }
01407 
01408 //------------------------------------------------------------------------------
01415 inline
01416 nString
01417 nString::ExtractLastDirName() const
01418 {
01419     nString pathString(*this);
01420     char* lastSlash = pathString.GetLastSlash();
01421 
01422     // special case if path ends with a slash
01423     if (lastSlash)
01424     {
01425         if (0 == lastSlash[1])
01426         {
01427             *lastSlash = 0;
01428             lastSlash = pathString.GetLastSlash();
01429         }
01430 
01431         char* secLastSlash = 0;
01432         if (0 != lastSlash)
01433         {
01434             *lastSlash = 0; // cut filename
01435             secLastSlash = pathString.GetLastSlash();
01436             if (secLastSlash)
01437             {
01438                 *secLastSlash = 0;
01439                 return nString(secLastSlash+1);
01440             }
01441         }
01442     }
01443     return "";
01444 }
01445 
01446 //------------------------------------------------------------------------------
01456 inline
01457 nString
01458 nString::ExtractDirName() const
01459 {
01460     nString pathString(*this);
01461     char* lastSlash = pathString.GetLastSlash();
01462 
01463     // special case if path ends with a slash
01464     if (lastSlash)
01465     {
01466         if (0 == lastSlash[1])
01467         {
01468             *lastSlash = 0;
01469             lastSlash = pathString.GetLastSlash();
01470         }
01471         if (lastSlash)
01472         {
01473             *++lastSlash = 0;
01474         }
01475     }
01476     pathString.SetLength(strlen(pathString.Get()));
01477     return pathString;
01478 }
01479 
01480 //------------------------------------------------------------------------------
01486 inline
01487 nString
01488 nString::ExtractToLastSlash() const
01489 {
01490     nString pathString(*this);
01491     char* lastSlash = pathString.GetLastSlash();
01492     if (lastSlash)
01493     {
01494         lastSlash[1] = 0;
01495     }
01496     else
01497     {
01498         pathString = "";
01499     }
01500     return pathString;
01501 }
01502 
01503 //------------------------------------------------------------------------------
01506 inline
01507 bool
01508 nString::MatchPattern(const nString& pattern) const
01509 {
01510     return n_strmatch(this->Get(), pattern.Get());
01511 }
01512 
01513 //------------------------------------------------------------------------------
01516 inline
01517 void
01518 nString::ReplaceChars(const char* charSet, char replacement)
01519 {
01520     n_assert(charSet);
01521     char* ptr = (char*)this->Get();
01522     char c;
01523     while (0 != (c = *ptr))
01524     {
01525         if (strchr(charSet, c))
01526         {
01527             *ptr = replacement;
01528         }
01529         ptr++;
01530     }
01531 }
01532 
01533 //------------------------------------------------------------------------------
01538 inline
01539 bool
01540 nString::CheckValidCharSet(const nString& charSet) const
01541 {
01542     int i;
01543     int len = this->Length();
01544     for (i = 0; i < len; i++)
01545     {
01546         if (-1 == charSet.FindCharIndex((*this)[i], 0))
01547         {
01548             return false;
01549         }
01550     }
01551     return true;
01552 }
01553 
01554 //------------------------------------------------------------------------------
01557 inline
01558 bool
01559 nString::IsValidInt() const
01560 {
01561     return this->CheckValidCharSet(" \t-+01234567890");
01562 }
01563 
01564 //------------------------------------------------------------------------------
01568 inline
01569 bool
01570 nString::IsValidFloat() const
01571 {
01572     return this->CheckValidCharSet(" \t-+.e1234567890");
01573 }
01574 
01575 //------------------------------------------------------------------------------
01578 inline
01579 bool
01580 nString::IsValidBool() const
01581 {
01582     static const char* bools[] = {
01583         "no", "yes", "off", "on", "false", "tr