00001
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <string.h>
00015 #include <ctype.h>
00016
00017 #include "CTB.hxx"
00018 #include "CTB_Trace.hxx"
00019 #include "CTBosFill.hxx"
00020 #include "CTBstring.hxx"
00021 #include "CTBnum.hxx"
00022 #include "CTBcstringBase.hxx"
00023
00029
00031
00035 static CTBint string_length(const char* c_str)
00036 {
00037 return c_str ? strlen(c_str) : 0;
00038 }
00039
00040
00042
00050 static CTBint string_length(const char* c_str, CTBint i_max)
00051 {
00052 CTBint i_len = 0;
00053
00054 while(i_max-- > 0 && *c_str++) i_len++;
00055
00056 return i_len;
00057 }
00058
00059
00061
00062 CTBstring::CTBstring(const CTBstring& rhs)
00063 : m_sbuf(rhs.m_sbuf),
00064 mi_offset(rhs.mi_offset),
00065 mi_length(rhs.mi_length)
00066 {
00067 CTB_Trace("CTBstring(const CTBstring&)");
00068 }
00069
00070
00072
00073 CTBstring::CTBstring(const CTBstring& rhs, CTBint i_length)
00074 : m_sbuf(rhs.m_sbuf),
00075 mi_offset(rhs.mi_offset),
00076 mi_length(CTBmin(CTBmax(0,i_length),rhs.Length()))
00077 {
00078 CTB_Trace("CTBstring(const CTBstring&, CTBint)");
00079 }
00080
00081
00083
00084 CTBstring::CTBstring(const CTBstring& rhs, CTBint i_offset, CTBint i_length)
00085 : m_sbuf(rhs.m_sbuf),
00086 mi_offset(0),
00087 mi_length(0)
00088 {
00089 CTB_Trace("CTBstring(const CTBstring&, CTBint, CTBint)");
00090 CTBint i_doff = CTBmin(CTBmax(0,i_offset),rhs.Length());
00091
00092 mi_offset = rhs.mi_offset + i_doff;
00093 mi_length = CTBmin(CTBmax(0,i_length),rhs.Length()-i_doff);
00094 }
00095
00096
00098
00099 CTBstring::CTBstring(const char* c_rhs)
00100 : m_sbuf(),
00101 mi_offset(0),
00102 mi_length(0)
00103 {
00104 CTB_Trace("CTBstring(const char*)");
00105 NewString(c_rhs,string_length(c_rhs));
00106 }
00107
00108
00110
00111 CTBstring::CTBstring(const char* c_rhs, CTBint i_length)
00112 : m_sbuf(),
00113 mi_offset(0),
00114 mi_length(0)
00115 {
00116 CTB_Trace("CTBstring(const char*, CTBint)");
00117 NewString(c_rhs,string_length(c_rhs,i_length));
00118 }
00119
00120
00122
00123 void CTBstring::Copy(const CTBstring& rhs)
00124 {
00125 CTB_Trace("CTBstring::Copy(const CTBstring&)");
00126
00127 m_sbuf = rhs.m_sbuf;
00128 mi_offset = rhs.mi_offset;
00129 mi_length = rhs.mi_length;
00130 return;
00131 }
00132
00133
00135
00136 void CTBstring::Copy(const char* c_rhs)
00137 {
00138 CTB_Trace("CTBstring::Copy(const char*)");
00139 NewString(c_rhs,string_length(c_rhs));
00140 return;
00141 }
00142
00143
00145
00146 void CTBstring::Copy(char c_rhs)
00147 {
00148 CTB_Trace("CTBstring::Copy(char)");
00149 char text[1];
00150
00151 text[0] = c_rhs;
00152 NewString(text,c_rhs ? 1 : 0);
00153 return;
00154 }
00155
00156
00158
00159 void CTBstring::Append(const CTBstring& rhs)
00160 {
00161 CTB_Trace("CTBstring::Append(const CTBstring&)");
00162 AppendData(rhs.Data(),rhs.Length());
00163 return;
00164 }
00165
00166
00168
00169 void CTBstring::Append(const char* c_rhs)
00170 {
00171 CTB_Trace("CTBstring::Append(const char*)");
00172 AppendData(c_rhs,string_length(c_rhs));
00173 return;
00174 }
00175
00176
00178
00179 void CTBstring::Append(const char* c_rhs, CTBint i_length)
00180 {
00181 CTB_Trace("CTBstring::Append(const char*, CTBint)");
00182 AppendData(c_rhs,string_length(c_rhs,i_length));
00183 return;
00184 }
00185
00186
00188
00189 void CTBstring::Append(char c_rhs)
00190 {
00191 CTB_Trace("CTBstring::Append(char)");
00192
00193 if (c_rhs != 0) {
00194
00195 if (mi_offset == 0 &&
00196 mi_length+2 <= m_sbuf.Size() &&
00197 m_sbuf.IsUnique()) {
00198 m_sbuf[mi_length] = c_rhs;
00199 mi_length += 1;
00200 m_sbuf[mi_length] = 0;
00201
00202 } else {
00203 char text[1];
00204 text[0] = c_rhs;
00205 AppendData(text,1);
00206 }
00207 }
00208 return;
00209 }
00210
00211
00213
00219 int CTBstring::Compare(const CTBstring& rhs) const
00220 {
00221 CTB_Trace("CTBstring::Compare(const CTBstring&)");
00222 CTBint i_len = CTBmin(Length(),rhs.Length());
00223 CTBint i_dif = strncmp(Data(),rhs.Data(),i_len);
00224
00225 if (i_dif == 0 && Length() != rhs.Length())
00226 i_dif = (Length() < rhs.Length()) ? 1 : -1;
00227
00228 return i_dif;
00229 }
00230
00231
00233
00239 int CTBstring::Compare(const char* c_rhs) const
00240 {
00241 CTB_Trace("CTBstring::Compare(const char*)");
00242 CTBint i_rhslen = string_length(c_rhs);
00243 CTBint i_len = CTBmin(Length(),i_rhslen);
00244 CTBint i_dif = strncmp(Data(),c_rhs,i_len);
00245
00246 if (i_dif == 0 && Length() != i_rhslen)
00247 i_dif = (Length() < i_rhslen) ? 1 : -1;
00248 return i_dif;
00249 }
00250
00251
00253
00259 int CTBstring::CompareCaseBlind(const CTBstring& rhs) const
00260 {
00261 CTB_Trace("CTBstring::CompareCaseBlind(const CTBstring&)");
00262 CTBint i_len = CTBmin(Length(),rhs.Length());
00263 const char* c_lhs = Data();
00264 const char* c_rhs = rhs.Data();
00265 int i_dif = 0;
00266
00267 for (CTBint i = 0; i < i_len; i++) {
00268 i_dif = tolower(*c_lhs++) - tolower(*c_rhs++);
00269 if (i_dif != 0) break;
00270 }
00271 return i_dif;
00272 }
00273
00274
00276
00282 int CTBstring::CompareCaseBlind(const char* c_rhs) const
00283 {
00284 CTB_Trace("CTBstring::CompareCaseBlind(const char*)");
00285 CTBint i_rhslen = string_length(c_rhs);
00286 CTBint i_len = CTBmin(Length(),i_rhslen);
00287 const char* c_lhs = Data();
00288 int i_dif = 0;
00289
00290 for (CTBint i = 0; i < i_len; i++) {
00291 i_dif = tolower(*c_lhs++) - tolower(*c_rhs++);
00292 if (i_dif != 0) break;
00293 }
00294 return i_dif;
00295 }
00296
00297
00299
00306 bool CTBstring::IsWhite() const
00307 {
00308 CTB_Trace("CTBstring::IsWhite()");
00309 if (mi_length > 0) {
00310 const char* p = Data();
00311 for (CTBint i = 0; i < mi_length; i++) if (!(isspace(*p++))) return false;
00312 }
00313 return true;
00314 }
00315
00316
00318
00322 bool CTBstring::IsUpperCase() const
00323 {
00324 CTB_Trace("CTBstring::IsUpperCase()");
00325 if (mi_length > 0) {
00326 const char* p = Data();
00327 for (CTBint i = 0; i < mi_length; i++) {
00328 char c = *p++;
00329 if (isalpha(c) && !(isupper(c))) return false;
00330 }
00331 }
00332 return true;
00333 }
00334
00335
00337
00341 bool CTBstring::IsLowerCase() const
00342 {
00343 CTB_Trace("CTBstring::IsLowerCase()");
00344 if (mi_length > 0) {
00345 const char* p = Data();
00346 for (CTBint i = 0; i < mi_length; i++) {
00347 char c = *p++;
00348 if (isalpha(c) && !(islower(c))) return false;
00349 }
00350 }
00351 return true;
00352 }
00353
00354
00356
00360 void CTBstring::TrimWhite()
00361 {
00362 CTB_Trace("CTBstring::TrimWhite()");
00363
00364 while (mi_length > 0) {
00365 if (!(isspace(m_sbuf[mi_offset]))) break;
00366 mi_offset += 1;
00367 mi_length -= 1;
00368 }
00369 while (mi_length > 0) {
00370 if (!(isspace(m_sbuf[mi_offset+mi_length-1]))) break;
00371 mi_length -= 1;
00372 }
00373 return;
00374 }
00375
00376
00378
00384 void CTBstring::CollapseWhite()
00385 {
00386 CTB_Trace("CTBstring::CollapseWhite()");
00387
00388 if (Length() == 0) return;
00389 Unshare();
00390
00391 char* pc_src = &m_sbuf[0];
00392 char* pc_dst = &m_sbuf[0];
00393 bool b_skip = false;
00394
00395 for (CTBint i = 0; i < mi_length; i++) {
00396 char c = *pc_src++;
00397 if (isspace(c)) {
00398 if (!b_skip) *pc_dst++ = ' ';
00399 b_skip = true;
00400 } else {
00401 *pc_dst++ = c;
00402 b_skip = false;
00403 }
00404 }
00405 mi_length = pc_dst - &m_sbuf[0];
00406 return;
00407 }
00408
00409
00411
00412 void CTBstring::ToUpperCase()
00413 {
00414 CTB_Trace("CTBstring::ToUpperCase()");
00415
00416 if (Length() == 0) return;
00417 Unshare();
00418
00419 for (CTBint i = 0; i < mi_length; i++) m_sbuf[i] = toupper(m_sbuf[i]);
00420
00421 return;
00422 }
00423
00424
00426
00427 void CTBstring::ToLowerCase()
00428 {
00429 CTB_Trace("CTBstring::ToLowerCase()");
00430
00431 if (Length() == 0) return;
00432 Unshare();
00433
00434 for (CTBint i = 0; i < mi_length; i++) m_sbuf[i] = tolower(m_sbuf[i]);
00435
00436 return;
00437 }
00438
00439
00441
00442 bool CTBstring::Get(long& i_val, int i_base) const
00443 {
00444 CTB_Trace("CTBstring::Get(long&,int)");
00445 CTBint i_size = (mi_length > 0 && Data()[mi_length] == 0) ? -1 : mi_length;
00446
00447 return CTBcstringBase::Get(Data(),i_size,i_val,i_base);
00448 }
00449
00450
00452
00453 bool CTBstring::Get(unsigned long& i_val, int i_base) const
00454 {
00455 CTB_Trace("CTBstring::Get(unsigned long&,int)");
00456 CTBint i_size = (mi_length > 0 && Data()[mi_length] == 0) ? -1 : mi_length;
00457
00458 return CTBcstringBase::Get(Data(),i_size,i_val,i_base);
00459 }
00460
00461
00463
00464 bool CTBstring::Get(int& i_val, int i_base) const
00465 {
00466 CTB_Trace("CTBstring::Get(int&,int)");
00467 CTBint i_size = (mi_length > 0 && Data()[mi_length] == 0) ? -1 : mi_length;
00468
00469 return CTBcstringBase::Get(Data(),i_size,i_val,i_base);
00470 }
00471
00472
00474
00475 bool CTBstring::Get(unsigned int& i_val, int i_base) const
00476 {
00477 CTB_Trace("CTBstring::Get(unsigned int&,int)");
00478 CTBint i_size = (mi_length > 0 && Data()[mi_length] == 0) ? -1 : mi_length;
00479
00480 return CTBcstringBase::Get(Data(),i_size,i_val,i_base);
00481 }
00482
00483
00485
00486 bool CTBstring::Get(double& d_val) const
00487 {
00488 CTB_Trace("CTBstring::Get(double&)");
00489 CTBint i_size = (mi_length > 0 && Data()[mi_length] == 0) ? -1 : mi_length;
00490
00491 return CTBcstringBase::Get(Data(),i_size,d_val);
00492 }
00493
00494
00496
00497 bool CTBstring::Get(float& f_val) const
00498 {
00499 CTB_Trace("CTBstring::Get(float&)");
00500 CTBint i_size = (mi_length > 0 && Data()[mi_length] == 0) ? -1 : mi_length;
00501
00502 return CTBcstringBase::Get(Data(),i_size,f_val);
00503 }
00504
00505
00507
00515 CTBint CTBstring::FindCharacter(const char* c_set, CTBint i_offset) const
00516 {
00517 return FindCharacter(c_set,string_length(c_set),i_offset);
00518 }
00519
00520
00522
00523 CTBstring CTBstring::Escape() const
00524 {
00525 CTB_Trace("CTBstring::Escape()");
00526
00527 if (Length() > 0 && FindCharacter("\f\n\r\t\v\\") != Length()) {
00528 CTBstring res;
00529 const char* p = Data();
00530
00531 for (CTBint i = 0; i < mi_length; i++) {
00532 char c = *p++;
00533 switch (c) {
00534 case '\f':
00535 res += "\\f";
00536 break;
00537 case '\n':
00538 res += "\\n";
00539 break;
00540 case '\r':
00541 res += "\\r";
00542 break;
00543 case '\t':
00544 res += "\\t";
00545 break;
00546 case '\v':
00547 res += "\\v";
00548 break;
00549 case '\\':
00550 res += "\\";
00551 break;
00552 default:
00553 res += c;
00554 break;
00555 }
00556 }
00557 return res;
00558 }
00559 return *this;
00560 }
00561
00562
00564
00565 CTBstring CTBstring::Unescape() const
00566 {
00567 CTB_Trace("CTBstring::Unscape()");
00568
00569 if (Length() > 0 && FindCharacter('\\') != Length()) {
00570 CTBstring res;
00571 const char* p = Data();
00572
00573 for (CTBint i = 0; i < mi_length; i++) {
00574 char c = *p++;
00575
00576 if (c == '\\' && i+1 < mi_length) {
00577 char c1 = *p++;
00578 i += 1;
00579
00580 switch (c1) {
00581
00582 case 'f':
00583 res += '\f';
00584 break;
00585 case 'n':
00586 res += '\n';
00587 break;
00588 case 'r':
00589 res += '\r';
00590 break;
00591 case 't':
00592 res += '\t';
00593 break;
00594 case 'v':
00595 res += '\v';
00596 break;
00597 case '\\':
00598 res += '\\';
00599 break;
00600
00601 case '\n':
00602 break;
00603
00604 default:
00605 res += c;
00606 res += c1;
00607 break;
00608 }
00609
00610 } else {
00611 res += c;
00612 }
00613 }
00614 return res;
00615 }
00616 return *this;
00617 }
00618
00619
00621
00625 bool CTBstring::GetLine(istream& is)
00626 {
00627 CTB_Trace("CTBstring::GetLine(istream&)");
00628 char buf[1024];
00629
00630 if (!is) return false;
00631
00632 buf[0] = 0;
00633 is.getline(buf,1024);
00634
00635 if (is.good() || (is.gcount() > 0 && is.eof())) {
00636 *this = buf;
00637 return true;
00638 }
00639 return false;
00640 }
00641
00642
00644
00645 void CTBstring::Dump(int i_indent, ostream& os, const char* p_text) const
00646 {
00647 CTBosFill bl(i_indent);
00648
00649 os << bl << "--CTBstring ";
00650 if (p_text) os << p_text;
00651 os << " @ " << this << endl;
00652 m_sbuf.Dump(i_indent+2,os,"m_sbuf");
00653 os << bl << " mi_offset: " << mi_offset << endl;
00654 os << bl << " mi_length: " << mi_length << endl;
00655 return;
00656 }
00657
00658
00660
00664 char CTBstring::operator[](CTBint i_ind) const
00665 {
00666 CTB_Trace("CTBstring::operator[](CTBint)");
00667
00668 if (i_ind < 0 && i_ind >= Length()) return 0;
00669 return Data()[i_ind];
00670 }
00671
00672
00674
00681 CTBstring::operator const char*() const
00682 {
00683 CTB_Trace("CTBstring::operator const char*()");
00684
00685 if (m_sbuf.IsNull()) return "";
00686
00687 ((CTBstring*) this) -> Terminate();
00688 return Data();
00689 }
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00711 CTBstring operator+(const CTBstring& lhs, const CTBstring& rhs)
00712 {
00713 CTB_Trace("operator+(const CTBstring&, const CTBstring&)");
00714 CTBstring res;
00715
00716 res.NewString(lhs.Data(),lhs.Length(),rhs.Data(),rhs.Length());
00717 return res;
00718 }
00719
00720
00726 CTBstring operator+(const CTBstring& lhs, const char* c_rhs)
00727 {
00728 CTB_Trace("operator+(const CTBstring&, const char*)");
00729 CTBstring res;
00730
00731 res.NewString(lhs.Data(),lhs.Length(),c_rhs,string_length(c_rhs));
00732 return res;
00733 }
00734
00735
00741 CTBstring operator+(const char* c_lhs, const CTBstring& rhs)
00742 {
00743 CTB_Trace("operator+(const char*, const CTBstring&)");
00744 CTBstring res;
00745
00746 res.NewString(c_lhs,string_length(c_lhs),rhs.Data(),rhs.Length());
00747 return res;
00748 }
00749
00750
00756 ostream& operator<<(ostream& os, const CTBstring& rhs)
00757 {
00759 if (rhs.Length() > 0) os.write(rhs.Data(),rhs.Length());
00760 return os;
00761 }
00762
00763
00765
00766 const CTBstring& CTBstring::NullString()
00767 {
00768 static const CTBstring nullstring;
00769 return nullstring;
00770 }
00771
00772
00774
00775 const CTBstring& CTBstring::EmptyString()
00776 {
00777 static const CTBstring emptystring("");
00778 return emptystring;
00779 }
00780
00781
00783
00784 void CTBstring::Unshare()
00785 {
00786 CTB_Trace("CTBstring::Unshare()");
00787 if (mi_offset > 0 ||
00788 m_sbuf.IsShared()) {
00789 CTBstring lhs(*this);
00790 NewString(lhs.Data(),lhs.Length());
00791 }
00792 return;
00793 }
00794
00795
00797
00804 void CTBstring::EnsureUnsharedCapacity(CTBint i_capacity)
00805 {
00806 CTB_Trace("CTBstring::EnsureUnsharedCapacity(CTBint)");
00807 CTBint i_size = i_capacity + 1;
00808
00809 i_size = i_size + 7;
00810 i_size = i_size - (i_size & 7);
00811
00812 if (m_sbuf.IsShared()) {
00813 m_sbuf.Resize(i_size);
00814 } else {
00815 CTBint i_oldsize = m_sbuf.Size();
00816 if (i_oldsize < i_size) {
00817 CTBint i_incsize = (i_oldsize <= 512) ? i_oldsize : i_oldsize/2;
00818 CTBint i_newsize = CTBmax(i_size,i_oldsize+i_incsize);
00819 m_sbuf.Resize(i_newsize);
00820 }
00821 }
00822 return;
00823 }
00824
00825
00827
00834 void CTBstring::NewString(const char* c_str, CTBint i_len)
00835 {
00836 CTB_Trace("CTBstring::NewString(const char*, CTBint)");
00837
00838 if (c_str) {
00839 EnsureUnsharedCapacity(i_len);
00840 if (i_len > 0) strncpy(&m_sbuf[0],c_str,i_len);
00841 m_sbuf[i_len] = 0;
00842 mi_length = i_len;
00843 mi_offset = 0;
00844
00845 } else {
00846 m_sbuf.Release();
00847 mi_length = 0;
00848 mi_offset = 0;
00849 }
00850
00851 return;
00852 }
00853
00854
00856
00864 void CTBstring::NewString(const char* c_str1, CTBint i_len1,
00865 const char* c_str2, CTBint i_len2)
00866 {
00867 CTB_Trace("CTBstring::NewString(const char*, CTBint, const char*, CTBint)");
00868
00869 if (c_str1 || c_str2) {
00870 CTBint i_length = i_len1 + i_len2;
00871
00872 EnsureUnsharedCapacity(i_length);
00873 if (i_len1 > 0) strncpy(&m_sbuf[0],c_str1,i_len1);
00874 if (i_len2 > 0) strncpy(&m_sbuf[i_len1],c_str2,i_len2);
00875 m_sbuf[i_length] = 0;
00876 mi_length = i_length;
00877 mi_offset = 0;
00878
00879 } else {
00880 m_sbuf.Release();
00881 mi_length = 0;
00882 mi_offset = 0;
00883 }
00884
00885 return;
00886 }
00887
00888
00890
00891 void CTBstring::AppendData(const char* c_str, CTBint i_len)
00892 {
00893 CTB_Trace("CTBstring::AppendData(const char*, CTBint");
00894
00895 if (i_len > 0) {
00896 CTBint i_oldlen = mi_length;
00897 CTBint i_newlen = i_oldlen + i_len;
00898
00899 if (mi_offset == 0 &&
00900 i_newlen+1 <= m_sbuf.Size() &&
00901 m_sbuf.IsUnique() ) {
00902 strncpy(&m_sbuf[mi_length],c_str,i_len);
00903 m_sbuf[i_newlen] = 0;
00904 mi_length = i_newlen;
00905
00906 } else {
00907 CTBstring lhs(*this, true);
00908 CTBint i_newcap = CTBmax(2*i_oldlen, i_newlen);
00909
00910 EnsureUnsharedCapacity(i_newcap);
00911 if (i_oldlen > 0) strncpy(&m_sbuf[0],lhs.Data(),i_oldlen);
00912 strncpy(&m_sbuf[i_oldlen],c_str,i_len);
00913 m_sbuf[i_newlen] = 0;
00914 mi_length = i_newlen;
00915 mi_offset = 0;
00916 }
00917 }
00918
00919 return;
00920 }
00921
00922
00924
00925 void CTBstring::Terminate()
00926 {
00927 CTB_Trace("CTBstring::Terminate()");
00928
00929 if (m_sbuf.IsNull()) return;
00930
00931 if (Data()[Length()] != 0) {
00932 if (m_sbuf.IsUnique()) {
00933 m_sbuf[mi_offset+mi_length] = 0;
00934 } else {
00935 NewString(Data(),Length());
00936 }
00937 }
00938 return;
00939 }
00940
00941
00943
00951 CTBint CTBstring::FindCharacter(const char* c_set, CTBint i_len,
00952 CTBint i_offset) const
00953 {
00954 CTB_Trace("CTBstring::FindCharacter(const char*, CTBint, CTBint)");
00955
00956 if (mi_length > 0 && i_offset < mi_length && i_len > 0) {
00957 CTBint i_off = CTBmax(0,i_offset);
00958
00959 for (CTBint i = i_off; i < mi_length; i++) {
00960 char c = m_sbuf[mi_offset+i];
00961
00962 for (CTBint j = 0; j < i_len; j++) {
00963 if (c == c_set[j]) return i;
00964 }
00965 }
00966 }
00967 return mi_length;
00968 }