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 }
KDE Home | KDE Accessibility Home | Description of Access Keys