ustring.cpp
00001 // -*- c-basic-offset: 2 -*- 00002 /* 00003 * This file is part of the KDE libraries 00004 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) 00005 * Copyright (C) 2003 Apple Computer, Inc. 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Library General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Library General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public License 00018 * along with this library; see the file COPYING.LIB. If not, write to 00019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 * Boston, MA 02110-1301, USA. 00021 * 00022 */ 00023 00024 #ifdef HAVE_CONFIG_H 00025 #include <config.h> 00026 #endif 00027 00028 #include <stdlib.h> 00029 #include <stdio.h> 00030 #include <ctype.h> 00031 #ifdef HAVE_STRING_H 00032 #include <string.h> 00033 #endif 00034 #ifdef HAVE_STRINGS_H 00035 #include <strings.h> 00036 #endif 00037 00038 #include "ustring.h" 00039 #include "operations.h" 00040 #include "identifier.h" 00041 #include <math.h> 00042 #include "dtoa.h" 00043 00044 namespace KJS { 00045 extern const double NaN; 00046 extern const double Inf; 00047 } 00048 00049 using namespace KJS; 00050 00051 CString::CString(const char *c) 00052 { 00053 length = strlen(c); 00054 data = new char[length+1]; 00055 memcpy(data, c, length + 1); 00056 } 00057 00058 CString::CString(const char *c, int len) 00059 { 00060 length = len; 00061 data = new char[len+1]; 00062 memcpy(data, c, len); 00063 data[len] = 0; 00064 } 00065 00066 CString::CString(const CString &b) 00067 { 00068 length = b.length; 00069 data = new char[length+1]; 00070 memcpy(data, b.data, length + 1); 00071 } 00072 00073 CString::~CString() 00074 { 00075 delete [] data; 00076 } 00077 00078 CString &CString::append(const CString &t) 00079 { 00080 char *n = new char[length + t.length + 1]; 00081 if (length) 00082 memcpy(n, data, length); 00083 if (t.length) 00084 memcpy(n+length, t.data, t.length); 00085 length += t.length; 00086 n[length] = 0; 00087 00088 delete [] data; 00089 data = n; 00090 00091 return *this; 00092 } 00093 00094 CString &CString::operator=(const char *c) 00095 { 00096 delete [] data; 00097 length = strlen(c); 00098 data = new char[length+1]; 00099 memcpy(data, c, length + 1); 00100 00101 return *this; 00102 } 00103 00104 CString &CString::operator=(const CString &str) 00105 { 00106 if (this == &str) 00107 return *this; 00108 00109 delete [] data; 00110 length = str.length; 00111 if (str.data) { 00112 data = new char[length + 1]; 00113 memcpy(data, str.data, length + 1); 00114 } 00115 else 00116 data = 0; 00117 00118 return *this; 00119 } 00120 00121 bool KJS::operator==(const KJS::CString& c1, const KJS::CString& c2) 00122 { 00123 int len = c1.size(); 00124 return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0); 00125 } 00126 00127 UChar UChar::null((char)0); 00128 UString::Rep UString::Rep::null = { 0, 0, 0, 1, 1 }; 00129 UString::Rep UString::Rep::empty = { 0, 0, 0, 1, 1 }; 00130 UString UString::null; 00131 static const int normalStatBufferSize = 4096; 00132 static char *statBuffer = 0; 00133 static int statBufferSize = 0; 00134 00135 UChar UChar::toLower() const 00136 { 00137 // ### properly support unicode tolower 00138 if (uc >= 256) 00139 return *this; 00140 00141 // tolower is locale-dependent, don't use it. 00142 return static_cast<unsigned char>( ( ( uc >= 'A' ) && ( uc <= 'Z' ) ) ? ( (int)uc + 'a' - 'A' ) : uc ); 00143 } 00144 00145 UChar UChar::toUpper() const 00146 { 00147 if (uc >= 256) 00148 return *this; 00149 00150 // toupper is locale-dependent, don't use it. 00151 return static_cast<unsigned char>( ( ( uc >= 'a' ) && ( uc <= 'z' ) ) ? ( (int)uc + 'A' - 'a' ) : uc ); 00152 } 00153 00154 UCharReference& UCharReference::operator=(UChar c) 00155 { 00156 str->detach(); 00157 if (offset < str->rep->len) 00158 *(str->rep->dat + offset) = c; 00159 /* TODO: lengthen string ? */ 00160 return *this; 00161 } 00162 00163 UChar& UCharReference::ref() const 00164 { 00165 if (offset < str->rep->len) 00166 return *(str->rep->dat + offset); 00167 else 00168 return UChar::null; 00169 } 00170 00171 // return an uninitialized UChar array of size s 00172 static inline UChar* allocateChars(int s) 00173 { 00174 // work around default UChar constructor code 00175 return reinterpret_cast<UChar*>(new short[s]); 00176 } 00177 00178 UString::Rep *UString::Rep::create(UChar *d, int l) 00179 { 00180 Rep *r = new Rep; 00181 r->dat = d; 00182 r->len = l; 00183 r->capacity = l; 00184 r->rc = 1; 00185 r->_hash = 0; 00186 return r; 00187 } 00188 00189 void UString::Rep::destroy() 00190 { 00191 if (capacity == capacityForIdentifier) 00192 Identifier::remove(this); 00193 delete [] dat; 00194 delete this; 00195 } 00196 00197 // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's 00198 // or anything like that. 00199 const unsigned PHI = 0x9e3779b9U; 00200 00201 // This hash algorithm comes from: 00202 // http://burtleburtle.net/bob/hash/hashfaq.html 00203 // http://burtleburtle.net/bob/hash/doobs.html 00204 unsigned UString::Rep::computeHash(const UChar *s, int length) 00205 { 00206 int prefixLength = length < 8 ? length : 8; 00207 int suffixPosition = length < 16 ? 8 : length - 8; 00208 00209 unsigned h = PHI; 00210 h += length; 00211 h += (h << 10); 00212 h ^= (h << 6); 00213 00214 for (int i = 0; i < prefixLength; i++) { 00215 h += s[i].uc; 00216 h += (h << 10); 00217 h ^= (h << 6); 00218 } 00219 for (int i = suffixPosition; i < length; i++){ 00220 h += s[i].uc; 00221 h += (h << 10); 00222 h ^= (h << 6); 00223 } 00224 00225 h += (h << 3); 00226 h ^= (h >> 11); 00227 h += (h << 15); 00228 00229 if (h == 0) 00230 h = 0x80000000; 00231 00232 return h; 00233 } 00234 00235 // This hash algorithm comes from: 00236 // http://burtleburtle.net/bob/hash/hashfaq.html 00237 // http://burtleburtle.net/bob/hash/doobs.html 00238 unsigned UString::Rep::computeHash(const char *s) 00239 { 00240 int length = strlen(s); 00241 int prefixLength = length < 8 ? length : 8; 00242 int suffixPosition = length < 16 ? 8 : length - 8; 00243 00244 unsigned h = PHI; 00245 h += length; 00246 h += (h << 10); 00247 h ^= (h << 6); 00248 00249 for (int i = 0; i < prefixLength; i++) { 00250 h += (unsigned char)s[i]; 00251 h += (h << 10); 00252 h ^= (h << 6); 00253 } 00254 for (int i = suffixPosition; i < length; i++) { 00255 h += (unsigned char)s[i]; 00256 h += (h << 10); 00257 h ^= (h << 6); 00258 } 00259 00260 h += (h << 3); 00261 h ^= (h >> 11); 00262 h += (h << 15); 00263 00264 if (h == 0) 00265 h = 0x80000000; 00266 00267 return h; 00268 } 00269 00270 UString::UString() 00271 { 00272 null.rep = &Rep::null; 00273 attach(&Rep::null); 00274 } 00275 00276 UString::UString(char c) 00277 { 00278 UChar *d = allocateChars(1); 00279 d[0] = c; 00280 rep = Rep::create(d, 1); 00281 } 00282 00283 UString::UString(const char *c) 00284 { 00285 if (!c) { 00286 attach(&Rep::null); 00287 return; 00288 } 00289 int length = strlen(c); 00290 if (length == 0) { 00291 attach(&Rep::empty); 00292 return; 00293 } 00294 UChar *d = new UChar[length]; 00295 for (int i = 0; i < length; i++) 00296 d[i].uc = (unsigned char)c[i]; 00297 rep = Rep::create(d, length); 00298 } 00299 00300 UString::UString(const UChar *c, int length) 00301 { 00302 if (length == 0) { 00303 attach(&Rep::empty); 00304 return; 00305 } 00306 UChar *d = allocateChars(length); 00307 memcpy(d, c, length * sizeof(UChar)); 00308 rep = Rep::create(d, length); 00309 } 00310 00311 UString::UString(UChar *c, int length, bool copy) 00312 { 00313 if (length == 0) { 00314 attach(&Rep::empty); 00315 return; 00316 } 00317 UChar *d; 00318 if (copy) { 00319 d = allocateChars(length); 00320 memcpy(d, c, length * sizeof(UChar)); 00321 } else 00322 d = c; 00323 rep = Rep::create(d, length); 00324 } 00325 00326 UString::UString(const UString &a, const UString &b) 00327 { 00328 int aSize = a.size(); 00329 int bSize = b.size(); 00330 int length = aSize + bSize; 00331 if (length == 0) { 00332 attach(&Rep::empty); 00333 return; 00334 } 00335 UChar *d = allocateChars(length); 00336 memcpy(d, a.data(), aSize * sizeof(UChar)); 00337 memcpy(d + aSize, b.data(), bSize * sizeof(UChar)); 00338 rep = Rep::create(d, length); 00339 } 00340 00341 UString UString::from(int i) 00342 { 00343 return from((long)i); 00344 } 00345 00346 UString UString::from(unsigned int u) 00347 { 00348 UChar buf[20]; 00349 UChar *end = buf + 20; 00350 UChar *p = end; 00351 00352 if (u == 0) { 00353 *--p = '0'; 00354 } else { 00355 while (u) { 00356 *--p = (unsigned short)((u % 10) + '0'); 00357 u /= 10; 00358 } 00359 } 00360 00361 return UString(p, end - p); 00362 } 00363 00364 UString UString::from(long l) 00365 { 00366 UChar buf[20]; 00367 UChar *end = buf + 20; 00368 UChar *p = end; 00369 00370 if (l == 0) { 00371 *--p = '0'; 00372 } else { 00373 bool negative = false; 00374 if (l < 0) { 00375 negative = true; 00376 l = -l; 00377 } 00378 while (l) { 00379 *--p = (unsigned short)((l % 10) + '0'); 00380 l /= 10; 00381 } 00382 if (negative) { 00383 *--p = '-'; 00384 } 00385 } 00386 00387 return UString(p, end - p); 00388 } 00389 00390 UString UString::from(double d) 00391 { 00392 char buf[80]; 00393 int decimalPoint; 00394 int sign; 00395 00396 char *result = kjs_dtoa(d, 0, 0, &decimalPoint, &sign, NULL); 00397 int length = strlen(result); 00398 00399 int i = 0; 00400 if (sign) { 00401 buf[i++] = '-'; 00402 } 00403 00404 if (decimalPoint <= 0 && decimalPoint > -6) { 00405 buf[i++] = '0'; 00406 buf[i++] = '.'; 00407 for (int j = decimalPoint; j < 0; j++) { 00408 buf[i++] = '0'; 00409 } 00410 strcpy(buf + i, result); 00411 } else if (decimalPoint <= 21 && decimalPoint > 0) { 00412 if (length <= decimalPoint) { 00413 strcpy(buf + i, result); 00414 i += length; 00415 for (int j = 0; j < decimalPoint - length; j++) { 00416 buf[i++] = '0'; 00417 } 00418 buf[i] = '\0'; 00419 } else { 00420 strncpy(buf + i, result, decimalPoint); 00421 i += decimalPoint; 00422 buf[i++] = '.'; 00423 strcpy(buf + i, result + decimalPoint); 00424 } 00425 } else if (result[0] < '0' || result[0] > '9') { 00426 strcpy(buf + i, result); 00427 } else { 00428 buf[i++] = result[0]; 00429 if (length > 1) { 00430 buf[i++] = '.'; 00431 strcpy(buf + i, result + 1); 00432 i += length - 1; 00433 } 00434 00435 buf[i++] = 'e'; 00436 buf[i++] = (decimalPoint >= 0) ? '+' : '-'; 00437 // decimalPoint can't be more than 3 digits decimal given the 00438 // nature of float representation 00439 int exponential = decimalPoint - 1; 00440 if (exponential < 0) { 00441 exponential = exponential * -1; 00442 } 00443 if (exponential >= 100) { 00444 buf[i++] = '0' + exponential / 100; 00445 } 00446 if (exponential >= 10) { 00447 buf[i++] = '0' + (exponential % 100) / 10; 00448 } 00449 buf[i++] = '0' + exponential % 10; 00450 buf[i++] = '\0'; 00451 } 00452 00453 kjs_freedtoa(result); 00454 00455 return UString(buf); 00456 } 00457 00458 UString &UString::append(const UString &t) 00459 { 00460 int l = size(); 00461 int tLen = t.size(); 00462 int newLen = l + tLen; 00463 if (rep->rc == 1 && newLen <= rep->capacity) { 00464 memcpy(rep->dat+l, t.data(), tLen * sizeof(UChar)); 00465 rep->len = newLen; 00466 rep->_hash = 0; 00467 return *this; 00468 } 00469 00470 int newCapacity = (newLen * 3 + 1) / 2; 00471 UChar *n = allocateChars(newCapacity); 00472 memcpy(n, data(), l * sizeof(UChar)); 00473 memcpy(n+l, t.data(), tLen * sizeof(UChar)); 00474 release(); 00475 rep = Rep::create(n, newLen); 00476 rep->capacity = newCapacity; 00477 00478 return *this; 00479 } 00480 00481 CString UString::cstring() const 00482 { 00483 return ascii(); 00484 } 00485 00486 char *UString::ascii() const 00487 { 00488 // Never make the buffer smaller than normalStatBufferSize. 00489 // Thus we almost never need to reallocate. 00490 int length = size(); 00491 int neededSize = length + 1; 00492 if (neededSize < normalStatBufferSize) { 00493 neededSize = normalStatBufferSize; 00494 } 00495 if (neededSize != statBufferSize) { 00496 delete [] statBuffer; 00497 statBuffer = new char [neededSize]; 00498 statBufferSize = neededSize; 00499 } 00500 00501 const UChar *p = data(); 00502 char *q = statBuffer; 00503 const UChar *limit = p + length; 00504 while (p != limit) { 00505 *q = p->uc; 00506 ++p; 00507 ++q; 00508 } 00509 *q = '\0'; 00510 00511 return statBuffer; 00512 } 00513 00514 #ifdef KJS_DEBUG_MEM 00515 void UString::globalClear() 00516 { 00517 delete [] statBuffer; 00518 statBuffer = 0; 00519 statBufferSize = 0; 00520 } 00521 #endif 00522 00523 UString &UString::operator=(const char *c) 00524 { 00525 int l = c ? strlen(c) : 0; 00526 UChar *d; 00527 if (rep->rc == 1 && l <= rep->capacity) { 00528 d = rep->dat; 00529 rep->_hash = 0; 00530 } else { 00531 release(); 00532 d = allocateChars(l); 00533 rep = Rep::create(d, l); 00534 } 00535 for (int i = 0; i < l; i++) 00536 d[i].uc = (unsigned char)c[i]; 00537 00538 return *this; 00539 } 00540 00541 UString &UString::operator=(const UString &str) 00542 { 00543 str.rep->ref(); 00544 release(); 00545 rep = str.rep; 00546 00547 return *this; 00548 } 00549 00550 bool UString::is8Bit() const 00551 { 00552 const UChar *u = data(); 00553 const UChar *limit = u + size(); 00554 while (u < limit) { 00555 if (u->uc > 0xFF) 00556 return false; 00557 ++u; 00558 } 00559 00560 return true; 00561 } 00562 00563 UChar UString::operator[](int pos) const 00564 { 00565 if (pos >= size()) 00566 return UChar::null; 00567 00568 return ((UChar *)data())[pos]; 00569 } 00570 00571 UCharReference UString::operator[](int pos) 00572 { 00573 /* TODO: boundary check */ 00574 return UCharReference(this, pos); 00575 } 00576 00577 static int skipInfString(const char *start) 00578 { 00579 const char *c = start; 00580 if (*c == '+' || *c == '-') 00581 c++; 00582 if (!strncmp(c,"Infinity",8)) 00583 return c+8-start; 00584 00585 while (*c >= '0' && *c <= '9') 00586 c++; 00587 const char * const at_dot = c; 00588 if (*c == '.') 00589 c++; 00590 while (*c >= '0' && *c <= '9') 00591 c++; 00592 00593 // don't accept a single dot as a number 00594 if (c - at_dot == 1 && *at_dot == '.') 00595 return at_dot-start; 00596 00597 if (*c != 'e') 00598 return c-start; 00599 00600 c++; 00601 if (*c == '+' || *c == '-') 00602 c++; 00603 while (*c >= '0' && *c <= '9') 00604 c++; 00605 return c-start; 00606 } 00607 00608 double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const 00609 { 00610 double d; 00611 double sign = 1; 00612 00613 // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk 00614 // after the number, so is8Bit is too strict a check. 00615 if (!is8Bit()) 00616 return NaN; 00617 00618 const char *c = ascii(); 00619 00620 // skip leading white space 00621 while (isspace(*c)) 00622 c++; 00623 00624 // empty string ? 00625 if (*c == '\0') 00626 return tolerateEmptyString ? 0.0 : NaN; 00627 00628 if (*c == '-') { 00629 sign = -1; 00630 c++; 00631 } 00632 else if (*c == '+') { 00633 sign = 1; 00634 c++; 00635 } 00636 00637 // hex number ? 00638 if (*c == '0' && (*(c+1) == 'x' || *(c+1) == 'X')) { 00639 c++; 00640 d = 0.0; 00641 while (*(++c)) { 00642 if (*c >= '0' && *c <= '9') 00643 d = d * 16.0 + *c - '0'; 00644 else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f')) 00645 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0; 00646 else 00647 break; 00648 } 00649 } else { 00650 // regular number ? 00651 char *end; 00652 d = kjs_strtod(c, &end); 00653 if ((d != 0.0 || end != c) && d != HUGE_VAL && d != -HUGE_VAL) { 00654 c = end; 00655 } else { 00656 // infinity ? 00657 00658 int count = skipInfString(c); 00659 if (count == 0) 00660 return NaN; 00661 d = Inf; 00662 c += count; 00663 } 00664 } 00665 00666 // allow trailing white space 00667 while (isspace(*c)) 00668 c++; 00669 // don't allow anything after - unless tolerant=true 00670 if (!tolerateTrailingJunk && *c != '\0') 00671 return NaN; 00672 00673 return d*sign; 00674 } 00675 00676 double UString::toDouble(bool tolerateTrailingJunk) const 00677 { 00678 return toDouble(tolerateTrailingJunk, true); 00679 } 00680 00681 double UString::toDouble() const 00682 { 00683 return toDouble(false, true); 00684 } 00685 00686 unsigned long UString::toULong(bool *ok, bool tolerateEmptyString) const 00687 { 00688 double d = toDouble(false, tolerateEmptyString); 00689 bool b = true; 00690 00691 if (isNaN(d) || d != static_cast<unsigned long>(d)) { 00692 b = false; 00693 d = 0; 00694 } 00695 00696 if (ok) 00697 *ok = b; 00698 00699 return static_cast<unsigned long>(d); 00700 } 00701 00702 unsigned long UString::toULong(bool *ok) const 00703 { 00704 return toULong(ok, true); 00705 } 00706 00707 UString UString::toLower() const 00708 { 00709 UString u = *this; 00710 for (int i = 0; i < size(); i++) 00711 u[i] = u[i].toLower(); 00712 return u; 00713 } 00714 00715 UString UString::toUpper() const 00716 { 00717 UString u = *this; 00718 for (int i = 0; i < size(); i++) 00719 u[i] = u[i].toUpper(); 00720 return u; 00721 } 00722 00723 unsigned int UString::toUInt32(bool *ok) const 00724 { 00725 double d = toDouble(); 00726 bool b = true; 00727 00728 if (isNaN(d) || d != static_cast<unsigned>(d)) { 00729 b = false; 00730 d = 0; 00731 } 00732 00733 if (ok) 00734 *ok = b; 00735 00736 return static_cast<unsigned>(d); 00737 } 00738 00739 unsigned int UString::toStrictUInt32(bool *ok) const 00740 { 00741 if (ok) 00742 *ok = false; 00743 00744 // Empty string is not OK. 00745 int len = rep->len; 00746 if (len == 0) 00747 return 0; 00748 const UChar *p = rep->dat; 00749 unsigned short c = p->unicode(); 00750 00751 // If the first digit is 0, only 0 itself is OK. 00752 if (c == '0') { 00753 if (len == 1 && ok) 00754 *ok = true; 00755 return 0; 00756 } 00757 00758 // Convert to UInt32, checking for overflow. 00759 unsigned int i = 0; 00760 while (1) { 00761 // Process character, turning it into a digit. 00762 if (c < '0' || c > '9') 00763 return 0; 00764 const unsigned d = c - '0'; 00765 00766 // Multiply by 10, checking for overflow out of 32 bits. 00767 if (i > 0xFFFFFFFFU / 10) 00768 return 0; 00769 i *= 10; 00770 00771 // Add in the digit, checking for overflow out of 32 bits. 00772 const unsigned max = 0xFFFFFFFFU - d; 00773 if (i > max) 00774 return 0; 00775 i += d; 00776 00777 // Handle end of string. 00778 if (--len == 0) { 00779 if (ok) 00780 *ok = true; 00781 return i; 00782 } 00783 00784 // Get next character. 00785 c = (++p)->unicode(); 00786 } 00787 } 00788 00789 // Rule from ECMA 15.2 about what an array index is. 00790 // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1. 00791 unsigned UString::toArrayIndex(bool *ok) const 00792 { 00793 unsigned i = toStrictUInt32(ok); 00794 if (i >= 0xFFFFFFFFU && ok) 00795 *ok = false; 00796 return i; 00797 } 00798 00799 int UString::find(const UString &f, int pos) const 00800 { 00801 int sz = size(); 00802 int fsz = f.size(); 00803 if (sz < fsz) 00804 return -1; 00805 if (pos < 0) 00806 pos = 0; 00807 if (fsz == 0) 00808 return pos; 00809 const UChar *end = data() + sz - fsz; 00810 long fsizeminusone = (fsz - 1) * sizeof(UChar); 00811 const UChar *fdata = f.data(); 00812 unsigned short fchar = fdata->uc; 00813 ++fdata; 00814 for (const UChar *c = data() + pos; c <= end; c++) 00815 if (c->uc == fchar && !memcmp(c + 1, fdata, fsizeminusone)) 00816 return (c-data()); 00817 00818 return -1; 00819 } 00820 00821 int UString::find(UChar ch, int pos) const 00822 { 00823 if (pos < 0) 00824 pos = 0; 00825 const UChar *end = data() + size(); 00826 for (const UChar *c = data() + pos; c < end; c++) 00827 if (*c == ch) 00828 return (c-data()); 00829 00830 return -1; 00831 } 00832 00833 int UString::rfind(const UString &f, int pos) const 00834 { 00835 int sz = size(); 00836 int fsz = f.size(); 00837 if (sz < fsz) 00838 return -1; 00839 if (pos < 0) 00840 pos = 0; 00841 if (pos > sz - fsz) 00842 pos = sz - fsz; 00843 if (fsz == 0) 00844 return pos; 00845 long fsizeminusone = (fsz - 1) * sizeof(UChar); 00846 const UChar *fdata = f.data(); 00847 for (const UChar *c = data() + pos; c >= data(); c--) { 00848 if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone)) 00849 return (c-data()); 00850 } 00851 00852 return -1; 00853 } 00854 00855 int UString::rfind(UChar ch, int pos) const 00856 { 00857 if (isEmpty()) 00858 return -1; 00859 if (pos + 1 >= size()) 00860 pos = size() - 1; 00861 for (const UChar *c = data() + pos; c >= data(); c--) { 00862 if (*c == ch) 00863 return (c-data()); 00864 } 00865 00866 return -1; 00867 } 00868 00869 UString UString::substr(int pos, int len) const 00870 { 00871 if (pos < 0) 00872 pos = 0; 00873 else if (pos >= (int) size()) 00874 pos = size(); 00875 if (len < 0) 00876 len = size(); 00877 if (pos + len >= (int) size()) 00878 len = size() - pos; 00879 00880 UChar *tmp = allocateChars(len); 00881 memcpy(tmp, data()+pos, len * sizeof(UChar)); 00882 UString result(tmp, len); 00883 delete [] tmp; 00884 00885 return result; 00886 } 00887 00888 void UString::attach(Rep *r) 00889 { 00890 rep = r; 00891 rep->ref(); 00892 } 00893 00894 void UString::detach() 00895 { 00896 if (rep->rc > 1) { 00897 int l = size(); 00898 UChar *n = allocateChars(l); 00899 memcpy(n, data(), l * sizeof(UChar)); 00900 release(); 00901 rep = Rep::create(n, l); 00902 } 00903 } 00904 00905 void UString::release() 00906 { 00907 rep->deref(); 00908 } 00909 00910 bool KJS::operator==(const UString& s1, const UString& s2) 00911 { 00912 if (s1.rep->len != s2.rep->len) 00913 return false; 00914 00915 #ifndef NDEBUG 00916 if ((s1.isNull() && s2.isEmpty() && !s2.isNull()) || 00917 (s2.isNull() && s1.isEmpty() && !s1.isNull())) 00918 fprintf(stderr, 00919 "KJS warning: comparison between empty and null string\n"); 00920 #endif 00921 00922 return (memcmp(s1.rep->dat, s2.rep->dat, 00923 s1.rep->len * sizeof(UChar)) == 0); 00924 } 00925 00926 bool KJS::operator==(const UString& s1, const char *s2) 00927 { 00928 if (s2 == 0) { 00929 return s1.isEmpty(); 00930 } 00931 00932 const UChar *u = s1.data(); 00933 const UChar *uend = u + s1.size(); 00934 while (u != uend && *s2) { 00935 if (u->uc != (unsigned char)*s2) 00936 return false; 00937 s2++; 00938 u++; 00939 } 00940 00941 return u == uend && *s2 == 0; 00942 } 00943 00944 bool KJS::operator<(const UString& s1, const UString& s2) 00945 { 00946 const int l1 = s1.size(); 00947 const int l2 = s2.size(); 00948 const int lmin = l1 < l2 ? l1 : l2; 00949 const UChar *c1 = s1.data(); 00950 const UChar *c2 = s2.data(); 00951 int l = 0; 00952 while (l < lmin && *c1 == *c2) { 00953 c1++; 00954 c2++; 00955 l++; 00956 } 00957 if (l < lmin) 00958 return (c1->uc < c2->uc); 00959 00960 return (l1 < l2); 00961 } 00962 00963 int KJS::compare(const UString& s1, const UString& s2) 00964 { 00965 const int l1 = s1.size(); 00966 const int l2 = s2.size(); 00967 const int lmin = l1 < l2 ? l1 : l2; 00968 const UChar *c1 = s1.data(); 00969 const UChar *c2 = s2.data(); 00970 int l = 0; 00971 while (l < lmin && *c1 == *c2) { 00972 c1++; 00973 c2++; 00974 l++; 00975 } 00976 if (l < lmin) 00977 return (c1->uc > c2->uc) ? 1 : -1; 00978 00979 if (l1 == l2) { 00980 return 0; 00981 } 00982 return (l1 < l2) ? 1 : -1; 00983 }