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