00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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 data = new char[length + 1];
00112 memcpy(data, str.data, length + 1);
00113
00114 return *this;
00115 }
00116
00117 bool KJS::operator==(const KJS::CString& c1, const KJS::CString& c2)
00118 {
00119 int len = c1.size();
00120 return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0);
00121 }
00122
00123 UChar UChar::null((char)0);
00124 UString::Rep UString::Rep::null = { 0, 0, 0, 1, 1 };
00125 UString::Rep UString::Rep::empty = { 0, 0, 0, 1, 1 };
00126 UString UString::null;
00127 static const int normalStatBufferSize = 4096;
00128 static char *statBuffer = 0;
00129 static int statBufferSize = 0;
00130
00131 UChar UChar::toLower() const
00132 {
00133
00134 if (uc >= 256 || islower(uc))
00135 return *this;
00136
00137 return (unsigned char)tolower(uc);
00138 }
00139
00140 UChar UChar::toUpper() const
00141 {
00142 if (uc >= 256 || isupper(uc))
00143 return *this;
00144
00145 return (unsigned char)toupper(uc);
00146 }
00147
00148 UCharReference& UCharReference::operator=(UChar c)
00149 {
00150 str->detach();
00151 if (offset < str->rep->len)
00152 *(str->rep->dat + offset) = c;
00153
00154 return *this;
00155 }
00156
00157 UChar& UCharReference::ref() const
00158 {
00159 if (offset < str->rep->len)
00160 return *(str->rep->dat + offset);
00161 else
00162 return UChar::null;
00163 }
00164
00165
00166 static inline UChar* allocateChars(int s)
00167 {
00168
00169 return reinterpret_cast<UChar*>(new short[s]);
00170 }
00171
00172 UString::Rep *UString::Rep::create(UChar *d, int l)
00173 {
00174 Rep *r = new Rep;
00175 r->dat = d;
00176 r->len = l;
00177 r->capacity = l;
00178 r->rc = 1;
00179 r->_hash = 0;
00180 return r;
00181 }
00182
00183 void UString::Rep::destroy()
00184 {
00185 if (capacity == capacityForIdentifier)
00186 Identifier::remove(this);
00187 delete [] dat;
00188 delete this;
00189 }
00190
00191
00192
00193 const unsigned PHI = 0x9e3779b9U;
00194
00195
00196
00197
00198 unsigned UString::Rep::computeHash(const UChar *s, int length)
00199 {
00200 int prefixLength = length < 8 ? length : 8;
00201 int suffixPosition = length < 16 ? 8 : length - 8;
00202
00203 unsigned h = PHI;
00204 h += length;
00205 h += (h << 10);
00206 h ^= (h << 6);
00207
00208 for (int i = 0; i < prefixLength; i++) {
00209 h += s[i].uc;
00210 h += (h << 10);
00211 h ^= (h << 6);
00212 }
00213 for (int i = suffixPosition; i < length; i++){
00214 h += s[i].uc;
00215 h += (h << 10);
00216 h ^= (h << 6);
00217 }
00218
00219 h += (h << 3);
00220 h ^= (h >> 11);
00221 h += (h << 15);
00222
00223 if (h == 0)
00224 h = 0x80000000;
00225
00226 return h;
00227 }
00228
00229
00230
00231
00232 unsigned UString::Rep::computeHash(const char *s)
00233 {
00234 int length = strlen(s);
00235 int prefixLength = length < 8 ? length : 8;
00236 int suffixPosition = length < 16 ? 8 : length - 8;
00237
00238 unsigned h = PHI;
00239 h += length;
00240 h += (h << 10);
00241 h ^= (h << 6);
00242
00243 for (int i = 0; i < prefixLength; i++) {
00244 h += (unsigned char)s[i];
00245 h += (h << 10);
00246 h ^= (h << 6);
00247 }
00248 for (int i = suffixPosition; i < length; i++) {
00249 h += (unsigned char)s[i];
00250 h += (h << 10);
00251 h ^= (h << 6);
00252 }
00253
00254 h += (h << 3);
00255 h ^= (h >> 11);
00256 h += (h << 15);
00257
00258 if (h == 0)
00259 h = 0x80000000;
00260
00261 return h;
00262 }
00263
00264 UString::UString()
00265 {
00266 null.rep = &Rep::null;
00267 attach(&Rep::null);
00268 }
00269
00270 UString::UString(char c)
00271 {
00272 UChar *d = allocateChars(1);
00273 d[0] = c;
00274 rep = Rep::create(d, 1);
00275 }
00276
00277 UString::UString(const char *c)
00278 {
00279 if (!c) {
00280 attach(&Rep::null);
00281 return;
00282 }
00283 int length = strlen(c);
00284 if (length == 0) {
00285 attach(&Rep::empty);
00286 return;
00287 }
00288 UChar *d = new UChar[length];
00289 for (int i = 0; i < length; i++)
00290 d[i].uc = c[i];
00291 rep = Rep::create(d, length);
00292 }
00293
00294 UString::UString(const UChar *c, int length)
00295 {
00296 if (length == 0) {
00297 attach(&Rep::empty);
00298 return;
00299 }
00300 UChar *d = allocateChars(length);
00301 memcpy(d, c, length * sizeof(UChar));
00302 rep = Rep::create(d, length);
00303 }
00304
00305 UString::UString(UChar *c, int length, bool copy)
00306 {
00307 if (length == 0) {
00308 attach(&Rep::empty);
00309 return;
00310 }
00311 UChar *d;
00312 if (copy) {
00313 d = allocateChars(length);
00314 memcpy(d, c, length * sizeof(UChar));
00315 } else
00316 d = c;
00317 rep = Rep::create(d, length);
00318 }
00319
00320 UString::UString(const UString &a, const UString &b)
00321 {
00322 int aSize = a.size();
00323 int bSize = b.size();
00324 int length = aSize + bSize;
00325 if (length == 0) {
00326 attach(&Rep::empty);
00327 return;
00328 }
00329 UChar *d = allocateChars(length);
00330 memcpy(d, a.data(), aSize * sizeof(UChar));
00331 memcpy(d + aSize, b.data(), bSize * sizeof(UChar));
00332 rep = Rep::create(d, length);
00333 }
00334
00335 UString UString::from(int i)
00336 {
00337 return from((long)i);
00338 }
00339
00340 UString UString::from(unsigned int u)
00341 {
00342 UChar buf[20];
00343 UChar *end = buf + 20;
00344 UChar *p = end;
00345
00346 if (u == 0) {
00347 *--p = '0';
00348 } else {
00349 while (u) {
00350 *--p = (unsigned short)((u % 10) + '0');
00351 u /= 10;
00352 }
00353 }
00354
00355 return UString(p, end - p);
00356 }
00357
00358 UString UString::from(long l)
00359 {
00360 UChar buf[20];
00361 UChar *end = buf + 20;
00362 UChar *p = end;
00363
00364 if (l == 0) {
00365 *--p = '0';
00366 } else {
00367 bool negative = false;
00368 if (l < 0) {
00369 negative = true;
00370 l = -l;
00371 }
00372 while (l) {
00373 *--p = (unsigned short)((l % 10) + '0');
00374 l /= 10;
00375 }
00376 if (negative) {
00377 *--p = '-';
00378 }
00379 }
00380
00381 return UString(p, end - p);
00382 }
00383
00384 UString UString::from(double d)
00385 {
00386 char buf[80];
00387 int decimalPoint;
00388 int sign;
00389
00390 char *result = kjs_dtoa(d, 0, 0, &decimalPoint, &sign, NULL);
00391 int length = strlen(result);
00392
00393 int i = 0;
00394 if (sign) {
00395 buf[i++] = '-';
00396 }
00397
00398 if (decimalPoint <= 0 && decimalPoint > -6) {
00399 buf[i++] = '0';
00400 buf[i++] = '.';
00401 for (int j = decimalPoint; j < 0; j++) {
00402 buf[i++] = '0';
00403 }
00404 strcpy(buf + i, result);
00405 } else if (decimalPoint <= 21 && decimalPoint > 0) {
00406 if (length <= decimalPoint) {
00407 strcpy(buf + i, result);
00408 i += length;
00409 for (int j = 0; j < decimalPoint - length; j++) {
00410 buf[i++] = '0';
00411 }
00412 buf[i] = '\0';
00413 } else {
00414 strncpy(buf + i, result, decimalPoint);
00415 i += decimalPoint;
00416 buf[i++] = '.';
00417 strcpy(buf + i, result + decimalPoint);
00418 }
00419 } else if (result[0] < '0' || result[0] > '9') {
00420 strcpy(buf + i, result);
00421 } else {
00422 buf[i++] = result[0];
00423 if (length > 1) {
00424 buf[i++] = '.';
00425 strcpy(buf + i, result + 1);
00426 i += length - 1;
00427 }
00428
00429 buf[i++] = 'e';
00430 buf[i++] = (decimalPoint >= 0) ? '+' : '-';
00431
00432
00433 int exponential = decimalPoint - 1;
00434 if (exponential < 0) {
00435 exponential = exponential * -1;
00436 }
00437 if (exponential >= 100) {
00438 buf[i++] = '0' + exponential / 100;
00439 }
00440 if (exponential >= 10) {
00441 buf[i++] = '0' + (exponential % 100) / 10;
00442 }
00443 buf[i++] = '0' + exponential % 10;
00444 buf[i++] = '\0';
00445 }
00446
00447 kjs_freedtoa(result);
00448
00449 return UString(buf);
00450 }
00451
00452 UString &UString::append(const UString &t)
00453 {
00454 int l = size();
00455 int tLen = t.size();
00456 int newLen = l + tLen;
00457 if (rep->rc == 1 && newLen <= rep->capacity) {
00458 memcpy(rep->dat+l, t.data(), tLen * sizeof(UChar));
00459 rep->len = newLen;
00460 rep->_hash = 0;
00461 return *this;
00462 }
00463
00464 int newCapacity = (newLen * 3 + 1) / 2;
00465 UChar *n = allocateChars(newCapacity);
00466 memcpy(n, data(), l * sizeof(UChar));
00467 memcpy(n+l, t.data(), tLen * sizeof(UChar));
00468 release();
00469 rep = Rep::create(n, newLen);
00470 rep->capacity = newCapacity;
00471
00472 return *this;
00473 }
00474
00475 CString UString::cstring() const
00476 {
00477 return ascii();
00478 }
00479
00480 char *UString::ascii() const
00481 {
00482
00483
00484 int length = size();
00485 int neededSize = length + 1;
00486 if (neededSize < normalStatBufferSize) {
00487 neededSize = normalStatBufferSize;
00488 }
00489 if (neededSize != statBufferSize) {
00490 delete [] statBuffer;
00491 statBuffer = new char [neededSize];
00492 statBufferSize = neededSize;
00493 }
00494
00495 const UChar *p = data();
00496 char *q = statBuffer;
00497 const UChar *limit = p + length;
00498 while (p != limit) {
00499 *q = p->uc;
00500 ++p;
00501 ++q;
00502 }
00503 *q = '\0';
00504
00505 return statBuffer;
00506 }
00507
00508 #ifdef KJS_DEBUG_MEM
00509 void UString::globalClear()
00510 {
00511 delete [] statBuffer;
00512 statBuffer = 0;
00513 statBufferSize = 0;
00514 }
00515 #endif
00516
00517 UString &UString::operator=(const char *c)
00518 {
00519 int l = c ? strlen(c) : 0;
00520 UChar *d;
00521 if (rep->rc == 1 && l <= rep->capacity) {
00522 d = rep->dat;
00523 rep->_hash = 0;
00524 } else {
00525 release();
00526 d = allocateChars(l);
00527 rep = Rep::create(d, l);
00528 }
00529 for (int i = 0; i < l; i++)
00530 d[i].uc = c[i];
00531
00532 return *this;
00533 }
00534
00535 UString &UString::operator=(const UString &str)
00536 {
00537 str.rep->ref();
00538 release();
00539 rep = str.rep;
00540
00541 return *this;
00542 }
00543
00544 bool UString::is8Bit() const
00545 {
00546 const UChar *u = data();
00547 const UChar *limit = u + size();
00548 while (u < limit) {
00549 if (u->uc > 0xFF)
00550 return false;
00551 ++u;
00552 }
00553
00554 return true;
00555 }
00556
00557 UChar UString::operator[](int pos) const
00558 {
00559 if (pos >= size())
00560 return UChar::null;
00561
00562 return ((UChar *)data())[pos];
00563 }
00564
00565 UCharReference UString::operator[](int pos)
00566 {
00567
00568 return UCharReference(this, pos);
00569 }
00570
00571 static int skipInfString(const char *start)
00572 {
00573 const char *c = start;
00574 if (*c == '+' || *c == '-')
00575 c++;
00576 if (!strncmp(c,"Infinity",8))
00577 return c+8-start;
00578
00579 while (*c >= '0' && *c <= '9')
00580 c++;
00581 if (*c == '.')
00582 c++;
00583 while (*c >= '0' && *c <= '9')
00584 c++;
00585
00586 if (*c != 'e')
00587 return c-start;
00588
00589 c++;
00590 if (*c == '+' || *c == '-')
00591 c++;
00592 while (*c >= '0' && *c <= '9')
00593 c++;
00594 return c-start;
00595 }
00596
00597 double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
00598 {
00599 double d;
00600 double sign = 1;
00601
00602
00603
00604 if (!is8Bit())
00605 return NaN;
00606
00607 const char *c = ascii();
00608
00609
00610 while (isspace(*c))
00611 c++;
00612
00613
00614 if (*c == '\0')
00615 return tolerateEmptyString ? 0.0 : NaN;
00616
00617 if (*c == '-') {
00618 sign = -1;
00619 c++;
00620 }
00621 else if (*c == '+') {
00622 sign = 1;
00623 c++;
00624 }
00625
00626
00627 if (*c == '0' && (*(c+1) == 'x' || *(c+1) == 'X')) {
00628 c++;
00629 d = 0.0;
00630 while (*(++c)) {
00631 if (*c >= '0' && *c <= '9')
00632 d = d * 16.0 + *c - '0';
00633 else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f'))
00634 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
00635 else
00636 break;
00637 }
00638 } else {
00639
00640 char *end;
00641 d = kjs_strtod(c, &end);
00642 if ((d != 0.0 || end != c) && d != HUGE_VAL && d != -HUGE_VAL) {
00643 c = end;
00644 } else {
00645
00646
00647 int count = skipInfString(c);
00648 if (count == 0)
00649 return NaN;
00650 d = Inf;
00651 c += count;
00652 }
00653 }
00654
00655
00656 while (isspace(*c))
00657 c++;
00658
00659 if (!tolerateTrailingJunk && *c != '\0')
00660 return NaN;
00661
00662 return d*sign;
00663 }
00664
00665 double UString::toDouble(bool tolerateTrailingJunk) const
00666 {
00667 return toDouble(tolerateTrailingJunk, true);
00668 }
00669
00670 double UString::toDouble() const
00671 {
00672 return toDouble(false, true);
00673 }
00674
00675 unsigned long UString::toULong(bool *ok, bool tolerateEmptyString) const
00676 {
00677 double d = toDouble(false, tolerateEmptyString);
00678 bool b = true;
00679
00680 if (isNaN(d) || d != static_cast<unsigned long>(d)) {
00681 b = false;
00682 d = 0;
00683 }
00684
00685 if (ok)
00686 *ok = b;
00687
00688 return static_cast<unsigned long>(d);
00689 }
00690
00691 unsigned long UString::toULong(bool *ok) const
00692 {
00693 return toULong(ok, true);
00694 }
00695
00696 UString UString::toLower() const
00697 {
00698 UString u = *this;
00699 for (int i = 0; i < size(); i++)
00700 u[i] = u[i].toLower();
00701 return u;
00702 }
00703
00704 UString UString::toUpper() const
00705 {
00706 UString u = *this;
00707 for (int i = 0; i < size(); i++)
00708 u[i] = u[i].toUpper();
00709 return u;
00710 }
00711
00712 unsigned int UString::toUInt32(bool *ok) const
00713 {
00714 double d = toDouble();
00715 bool b = true;
00716
00717 if (isNaN(d) || d != static_cast<unsigned>(d)) {
00718 b = false;
00719 d = 0;
00720 }
00721
00722 if (ok)
00723 *ok = b;
00724
00725 return static_cast<unsigned>(d);
00726 }
00727
00728 unsigned int UString::toStrictUInt32(bool *ok) const
00729 {
00730 if (ok)
00731 *ok = false;
00732
00733
00734 int len = rep->len;
00735 if (len == 0)
00736 return 0;
00737 const UChar *p = rep->dat;
00738 unsigned short c = p->unicode();
00739
00740
00741 if (c == '0') {
00742 if (len == 1 && ok)
00743 *ok = true;
00744 return 0;
00745 }
00746
00747
00748 unsigned int i = 0;
00749 while (1) {
00750
00751 if (c < '0' || c > '9')
00752 return 0;
00753 const unsigned d = c - '0';
00754
00755
00756 if (i > 0xFFFFFFFFU / 10)
00757 return 0;
00758 i *= 10;
00759
00760
00761 const unsigned max = 0xFFFFFFFFU - d;
00762 if (i > max)
00763 return 0;
00764 i += d;
00765
00766
00767 if (--len == 0) {
00768 if (ok)
00769 *ok = true;
00770 return i;
00771 }
00772
00773
00774 c = (++p)->unicode();
00775 }
00776 }
00777
00778
00779
00780 unsigned UString::toArrayIndex(bool *ok) const
00781 {
00782 unsigned i = toStrictUInt32(ok);
00783 if (i >= 0xFFFFFFFFU && ok)
00784 *ok = false;
00785 return i;
00786 }
00787
00788 int UString::find(const UString &f, int pos) const
00789 {
00790 int sz = size();
00791 int fsz = f.size();
00792 if (sz < fsz)
00793 return -1;
00794 if (pos < 0)
00795 pos = 0;
00796 if (fsz == 0)
00797 return pos;
00798 const UChar *end = data() + sz - fsz;
00799 long fsizeminusone = (fsz - 1) * sizeof(UChar);
00800 const UChar *fdata = f.data();
00801 unsigned short fchar = fdata->uc;
00802 ++fdata;
00803 for (const UChar *c = data() + pos; c <= end; c++)
00804 if (c->uc == fchar && !memcmp(c + 1, fdata, fsizeminusone))
00805 return (c-data());
00806
00807 return -1;
00808 }
00809
00810 int UString::find(UChar ch, int pos) const
00811 {
00812 if (pos < 0)
00813 pos = 0;
00814 const UChar *end = data() + size();
00815 for (const UChar *c = data() + pos; c < end; c++)
00816 if (*c == ch)
00817 return (c-data());
00818
00819 return -1;
00820 }
00821
00822 int UString::rfind(const UString &f, int pos) const
00823 {
00824 int sz = size();
00825 int fsz = f.size();
00826 if (sz < fsz)
00827 return -1;
00828 if (pos < 0)
00829 pos = 0;
00830 if (pos > sz - fsz)
00831 pos = sz - fsz;
00832 if (fsz == 0)
00833 return pos;
00834 long fsizeminusone = (fsz - 1) * sizeof(UChar);
00835 const UChar *fdata = f.data();
00836 for (const UChar *c = data() + pos; c >= data(); c--) {
00837 if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone))
00838 return (c-data());
00839 }
00840
00841 return -1;
00842 }
00843
00844 int UString::rfind(UChar ch, int pos) const
00845 {
00846 if (isEmpty())
00847 return -1;
00848 if (pos + 1 >= size())
00849 pos = size() - 1;
00850 for (const UChar *c = data() + pos; c >= data(); c--) {
00851 if (*c == ch)
00852 return (c-data());
00853 }
00854
00855 return -1;
00856 }
00857
00858 UString UString::substr(int pos, int len) const
00859 {
00860 if (pos < 0)
00861 pos = 0;
00862 else if (pos >= (int) size())
00863 pos = size();
00864 if (len < 0)
00865 len = size();
00866 if (pos + len >= (int) size())
00867 len = size() - pos;
00868
00869 UChar *tmp = allocateChars(len);
00870 memcpy(tmp, data()+pos, len * sizeof(UChar));
00871 UString result(tmp, len);
00872 delete [] tmp;
00873
00874 return result;
00875 }
00876
00877 void UString::attach(Rep *r)
00878 {
00879 rep = r;
00880 rep->ref();
00881 }
00882
00883 void UString::detach()
00884 {
00885 if (rep->rc > 1) {
00886 int l = size();
00887 UChar *n = allocateChars(l);
00888 memcpy(n, data(), l * sizeof(UChar));
00889 release();
00890 rep = Rep::create(n, l);
00891 }
00892 }
00893
00894 void UString::release()
00895 {
00896 rep->deref();
00897 }
00898
00899 bool KJS::operator==(const UString& s1, const UString& s2)
00900 {
00901 if (s1.rep->len != s2.rep->len)
00902 return false;
00903
00904 return (memcmp(s1.rep->dat, s2.rep->dat,
00905 s1.rep->len * sizeof(UChar)) == 0);
00906 }
00907
00908 bool KJS::operator==(const UString& s1, const char *s2)
00909 {
00910 if (s2 == 0) {
00911 return s1.isEmpty();
00912 }
00913
00914 const UChar *u = s1.data();
00915 const UChar *uend = u + s1.size();
00916 while (u != uend && *s2) {
00917 if (u->uc != (unsigned char)*s2)
00918 return false;
00919 s2++;
00920 u++;
00921 }
00922
00923 return u == uend && *s2 == 0;
00924 }
00925
00926 bool KJS::operator<(const UString& s1, const UString& s2)
00927 {
00928 const int l1 = s1.size();
00929 const int l2 = s2.size();
00930 const int lmin = l1 < l2 ? l1 : l2;
00931 const UChar *c1 = s1.data();
00932 const UChar *c2 = s2.data();
00933 int l = 0;
00934 while (l < lmin && *c1 == *c2) {
00935 c1++;
00936 c2++;
00937 l++;
00938 }
00939 if (l < lmin)
00940 return (c1->uc < c2->uc);
00941
00942 return (l1 < l2);
00943 }
00944
00945 int KJS::compare(const UString& s1, const UString& s2)
00946 {
00947 const int l1 = s1.size();
00948 const int l2 = s2.size();
00949 const int lmin = l1 < l2 ? l1 : l2;
00950 const UChar *c1 = s1.data();
00951 const UChar *c2 = s2.data();
00952 int l = 0;
00953 while (l < lmin && *c1 == *c2) {
00954 c1++;
00955 c2++;
00956 l++;
00957 }
00958 if (l < lmin)
00959 return (c1->uc > c2->uc) ? 1 : -1;
00960
00961 if (l1 == l2) {
00962 return 0;
00963 }
00964 return (l1 < l2) ? 1 : -1;
00965 }