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
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
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
00886 while (*ptr && strchr(whiteSpace, *ptr))
00887 {
00888 ptr++;
00889 }
00890 if (*ptr)
00891 {
00892
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
01081 match = true;
01082 break;
01083 }
01084 }
01085 if (!match)
01086 {
01087
01088 stopped = true;
01089 }
01090 else
01091 {
01092
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
01127 match = true;
01128 break;
01129 }
01130 }
01131 if (!match)
01132 {
01133
01134 stopped = true;
01135 }
01136 else
01137 {
01138
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
01173 const char* occur;
01174 while ((occur = strstr(ptr, matchStr)))
01175 {
01176
01177 dest.AppendRange(ptr, occur - ptr);
01178
01179
01180 dest.Append(substStr);
01181
01182
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
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
01224 c = '?';
01225 src += 2;
01226 }
01227 else if ((c & 0xF8) == 0xF0)
01228 {
01229
01230 c = '?';
01231 src += 3;
01232 }
01233 else if ((c & 0xFC) == 0xF8)
01234 {
01235
01236 c = '?';
01237 src += 4;
01238 }
01239 else if ((c & 0xFE) == 0xFC)
01240 {
01241
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
01268
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
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;
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
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