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 || 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   /* TODO: lengthen string ? */
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 // return an uninitialized UChar array of size s
00166 static inline UChar* allocateChars(int s)
00167 {
00168   // work around default UChar constructor code
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 // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
00192 // or anything like that.
00193 const unsigned PHI = 0x9e3779b9U;
00194 
00195 // This hash algorithm comes from:
00196 // http://burtleburtle.net/bob/hash/hashfaq.html
00197 // http://burtleburtle.net/bob/hash/doobs.html
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 // This hash algorithm comes from:
00230 // http://burtleburtle.net/bob/hash/hashfaq.html
00231 // http://burtleburtle.net/bob/hash/doobs.html
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     // decimalPoint can't be more than 3 digits decimal given the
00432     // nature of float representation
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   // Never make the buffer smaller than normalStatBufferSize.
00483   // Thus we almost never need to reallocate.
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   /* TODO: boundary check */
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   const char * const at_dot = c;
00582   if (*c == '.')
00583     c++;
00584   while (*c >= '0' && *c <= '9')
00585     c++;
00586 
00587   // don't accept a single dot as a number
00588   if (c - at_dot == 1 && *at_dot == '.')
00589     return at_dot-start;
00590 
00591   if (*c != 'e')
00592     return c-start;
00593 
00594   c++;
00595   if (*c == '+' || *c == '-')
00596     c++;
00597   while (*c >= '0' && *c <= '9')
00598     c++;
00599   return c-start;
00600 }
00601 
00602 double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
00603 {
00604   double d;
00605   double sign = 1;
00606 
00607   // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk
00608   // after the number, so is8Bit is too strict a check.
00609   if (!is8Bit())
00610     return NaN;
00611 
00612   const char *c = ascii();
00613 
00614   // skip leading white space
00615   while (isspace(*c))
00616     c++;
00617 
00618   // empty string ?
00619   if (*c == '\0')
00620     return tolerateEmptyString ? 0.0 : NaN;
00621 
00622   if (*c == '-') {
00623     sign = -1;
00624     c++;
00625   }
00626   else if (*c == '+') {
00627     sign = 1;
00628     c++;
00629   }
00630 
00631   // hex number ?
00632   if (*c == '0' && (*(c+1) == 'x' || *(c+1) == 'X')) {
00633     c++;
00634     d = 0.0;
00635     while (*(++c)) {
00636       if (*c >= '0' && *c <= '9')
00637     d = d * 16.0 + *c - '0';
00638       else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f'))
00639     d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
00640       else
00641     break;
00642     }
00643   } else {
00644     // regular number ?
00645     char *end;
00646     d = kjs_strtod(c, &end);
00647     if ((d != 0.0 || end != c) && d != HUGE_VAL && d != -HUGE_VAL) {
00648       c = end;
00649     } else {
00650       // infinity ?
00651 
00652       int count = skipInfString(c);
00653       if (count == 0)
00654     return NaN;
00655       d = Inf;
00656       c += count;
00657     }
00658   }
00659 
00660   // allow trailing white space
00661   while (isspace(*c))
00662     c++;
00663   // don't allow anything after - unless tolerant=true
00664   if (!tolerateTrailingJunk && *c != '\0')
00665     return NaN;
00666 
00667   return d*sign;
00668 }
00669 
00670 double UString::toDouble(bool tolerateTrailingJunk) const
00671 {
00672   return toDouble(tolerateTrailingJunk, true);
00673 }
00674 
00675 double UString::toDouble() const
00676 {
00677   return toDouble(false, true);
00678 }
00679 
00680 unsigned long UString::toULong(bool *ok, bool tolerateEmptyString) const
00681 {
00682   double d = toDouble(false, tolerateEmptyString);
00683   bool b = true;
00684 
00685   if (isNaN(d) || d != static_cast<unsigned long>(d)) {
00686     b = false;
00687     d = 0;
00688   }
00689 
00690   if (ok)
00691     *ok = b;
00692 
00693   return static_cast<unsigned long>(d);
00694 }
00695 
00696 unsigned long UString::toULong(bool *ok) const
00697 {
00698   return toULong(ok, true);
00699 }
00700 
00701 UString UString::toLower() const
00702 {
00703   UString u = *this;
00704   for (int i = 0; i < size(); i++)
00705     u[i] = u[i].toLower();
00706   return u;
00707 }
00708 
00709 UString UString::toUpper() const
00710 {
00711   UString u = *this;
00712   for (int i = 0; i < size(); i++)
00713     u[i] = u[i].toUpper();
00714   return u;
00715 }
00716 
00717 unsigned int UString::toUInt32(bool *ok) const
00718 {
00719   double d = toDouble();
00720   bool b = true;
00721 
00722   if (isNaN(d) || d != static_cast<unsigned>(d)) {
00723     b = false;
00724     d = 0;
00725   }
00726 
00727   if (ok)
00728     *ok = b;
00729 
00730   return static_cast<unsigned>(d);
00731 }
00732 
00733 unsigned int UString::toStrictUInt32(bool *ok) const
00734 {
00735   if (ok)
00736     *ok = false;
00737 
00738   // Empty string is not OK.
00739   int len = rep->len;
00740   if (len == 0)
00741     return 0;
00742   const UChar *p = rep->dat;
00743   unsigned short c = p->unicode();
00744 
00745   // If the first digit is 0, only 0 itself is OK.
00746   if (c == '0') {
00747     if (len == 1 && ok)
00748       *ok = true;
00749     return 0;
00750   }
00751 
00752   // Convert to UInt32, checking for overflow.
00753   unsigned int i = 0;
00754   while (1) {
00755     // Process character, turning it into a digit.
00756     if (c < '0' || c > '9')
00757       return 0;
00758     const unsigned d = c - '0';
00759 
00760     // Multiply by 10, checking for overflow out of 32 bits.
00761     if (i > 0xFFFFFFFFU / 10)
00762       return 0;
00763     i *= 10;
00764 
00765     // Add in the digit, checking for overflow out of 32 bits.
00766     const unsigned max = 0xFFFFFFFFU - d;
00767     if (i > max)
00768         return 0;
00769     i += d;
00770 
00771     // Handle end of string.
00772     if (--len == 0) {
00773       if (ok)
00774         *ok = true;
00775       return i;
00776     }
00777 
00778     // Get next character.
00779     c = (++p)->unicode();
00780   }
00781 }
00782 
00783 // Rule from ECMA 15.2 about what an array index is.
00784 // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
00785 unsigned UString::toArrayIndex(bool *ok) const
00786 {
00787   unsigned i = toStrictUInt32(ok);
00788   if (i >= 0xFFFFFFFFU && ok)
00789     *ok = false;
00790   return i;
00791 }
00792 
00793 int UString::find(const UString &f, int pos) const
00794 {
00795   int sz = size();
00796   int fsz = f.size();
00797   if (sz < fsz)
00798     return -1;
00799   if (pos < 0)
00800     pos = 0;
00801   if (fsz == 0)
00802     return pos;
00803   const UChar *end = data() + sz - fsz;
00804   long fsizeminusone = (fsz - 1) * sizeof(UChar);
00805   const UChar *fdata = f.data();
00806   unsigned short fchar = fdata->uc;
00807   ++fdata;
00808   for (const UChar *c = data() + pos; c <= end; c++)
00809     if (c->uc == fchar && !memcmp(c + 1, fdata, fsizeminusone))
00810       return (c-data());
00811 
00812   return -1;
00813 }
00814 
00815 int UString::find(UChar ch, int pos) const
00816 {
00817   if (pos < 0)
00818     pos = 0;
00819   const UChar *end = data() + size();
00820   for (const UChar *c = data() + pos; c < end; c++)
00821     if (*c == ch)
00822       return (c-data());
00823 
00824   return -1;
00825 }
00826 
00827 int UString::rfind(const UString &f, int pos) const
00828 {
00829   int sz = size();
00830   int fsz = f.size();
00831   if (sz < fsz)
00832     return -1;
00833   if (pos < 0)
00834     pos = 0;
00835   if (pos > sz - fsz)
00836     pos = sz - fsz;
00837   if (fsz == 0)
00838     return pos;
00839   long fsizeminusone = (fsz - 1) * sizeof(UChar);
00840   const UChar *fdata = f.data();
00841   for (const UChar *c = data() + pos; c >= data(); c--) {
00842     if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone))
00843       return (c-data());
00844   }
00845 
00846   return -1;
00847 }
00848 
00849 int UString::rfind(UChar ch, int pos) const
00850 {
00851   if (isEmpty())
00852     return -1;
00853   if (pos + 1 >= size())
00854     pos = size() - 1;
00855   for (const UChar *c = data() + pos; c >= data(); c--) {
00856     if (*c == ch)
00857       return (c-data());
00858   }
00859 
00860   return -1;
00861 }
00862 
00863 UString UString::substr(int pos, int len) const
00864 {
00865   if (pos < 0)
00866     pos = 0;
00867   else if (pos >= (int) size())
00868     pos = size();
00869   if (len < 0)
00870     len = size();
00871   if (pos + len >= (int) size())
00872     len = size() - pos;
00873 
00874   UChar *tmp = allocateChars(len);
00875   memcpy(tmp, data()+pos, len * sizeof(UChar));
00876   UString result(tmp, len);
00877   delete [] tmp;
00878 
00879   return result;
00880 }
00881 
00882 void UString::attach(Rep *r)
00883 {
00884   rep = r;
00885   rep->ref();
00886 }
00887 
00888 void UString::detach()
00889 {
00890   if (rep->rc > 1) {
00891     int l = size();
00892     UChar *n = allocateChars(l);
00893     memcpy(n, data(), l * sizeof(UChar));
00894     release();
00895     rep = Rep::create(n, l);
00896   }
00897 }
00898 
00899 void UString::release()
00900 {
00901   rep->deref();
00902 }
00903 
00904 bool KJS::operator==(const UString& s1, const UString& s2)
00905 {
00906   if (s1.rep->len != s2.rep->len)
00907     return false;
00908 
00909 #ifndef NDEBUG
00910   if ((s1.isNull() && s2.isEmpty() && !s2.isNull()) ||
00911       (s2.isNull() && s1.isEmpty() && !s1.isNull()))
00912     fprintf(stderr,
00913             "KJS warning: comparison between empty and null string\n");
00914 #endif
00915 
00916   return (memcmp(s1.rep->dat, s2.rep->dat,
00917          s1.rep->len * sizeof(UChar)) == 0);
00918 }
00919 
00920 bool KJS::operator==(const UString& s1, const char *s2)
00921 {
00922   if (s2 == 0) {
00923     return s1.isEmpty();
00924   }
00925 
00926   const UChar *u = s1.data();
00927   const UChar *uend = u + s1.size();
00928   while (u != uend && *s2) {
00929     if (u->uc != (unsigned char)*s2)
00930       return false;
00931     s2++;
00932     u++;
00933   }
00934 
00935   return u == uend && *s2 == 0;
00936 }
00937 
00938 bool KJS::operator<(const UString& s1, const UString& s2)
00939 {
00940   const int l1 = s1.size();
00941   const int l2 = s2.size();
00942   const int lmin = l1 < l2 ? l1 : l2;
00943   const UChar *c1 = s1.data();
00944   const UChar *c2 = s2.data();
00945   int l = 0;
00946   while (l < lmin && *c1 == *c2) {
00947     c1++;
00948     c2++;
00949     l++;
00950   }
00951   if (l < lmin)
00952     return (c1->uc < c2->uc);
00953 
00954   return (l1 < l2);
00955 }
00956 
00957 int KJS::compare(const UString& s1, const UString& s2)
00958 {
00959   const int l1 = s1.size();
00960   const int l2 = s2.size();
00961   const int lmin = l1 < l2 ? l1 : l2;
00962   const UChar *c1 = s1.data();
00963   const UChar *c2 = s2.data();
00964   int l = 0;
00965   while (l < lmin && *c1 == *c2) {
00966     c1++;
00967     c2++;
00968     l++;
00969   }
00970   if (l < lmin)
00971     return (c1->uc > c2->uc) ? 1 : -1;
00972 
00973   if (l1 == l2) {
00974     return 0;
00975   }
00976   return (l1 < l2) ? 1 : -1;
00977 }
KDE Home | KDE Accessibility Home | Description of Access Keys