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 = 0L;
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 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::toStrictUInt32(bool *ok) const
00713 {
00714 if (ok)
00715 *ok = false;
00716
00717
00718 int len = rep->len;
00719 if (len == 0)
00720 return 0;
00721 const UChar *p = rep->dat;
00722 unsigned short c = p->unicode();
00723
00724
00725 if (c == '0') {
00726 if (len == 1 && ok)
00727 *ok = true;
00728 return 0;
00729 }
00730
00731
00732 unsigned int i = 0;
00733 while (1) {
00734
00735 if (c < '0' || c > '9')
00736 return 0;
00737 const unsigned d = c - '0';
00738
00739
00740 if (i > 0xFFFFFFFFU / 10)
00741 return 0;
00742 i *= 10;
00743
00744
00745 const unsigned max = 0xFFFFFFFFU - d;
00746 if (i > max)
00747 return 0;
00748 i += d;
00749
00750
00751 if (--len == 0) {
00752 if (ok)
00753 *ok = true;
00754 return i;
00755 }
00756
00757
00758 c = (++p)->unicode();
00759 }
00760 }
00761
00762
00763
00764 unsigned UString::toArrayIndex(bool *ok) const
00765 {
00766 unsigned i = toStrictUInt32(ok);
00767 if (i >= 0xFFFFFFFFU && ok)
00768 *ok = false;
00769 return i;
00770 }
00771
00772 int UString::find(const UString &f, int pos) const
00773 {
00774 int sz = size();
00775 int fsz = f.size();
00776 if (sz < fsz)
00777 return -1;
00778 if (pos < 0)
00779 pos = 0;
00780 if (fsz == 0)
00781 return pos;
00782 const UChar *end = data() + sz - fsz;
00783 long fsizeminusone = (fsz - 1) * sizeof(UChar);
00784 const UChar *fdata = f.data();
00785 for (const UChar *c = data() + pos; c <= end; c++)
00786 if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone))
00787 return (c-data());
00788
00789 return -1;
00790 }
00791
00792 int UString::find(UChar ch, int pos) const
00793 {
00794 if (pos < 0)
00795 pos = 0;
00796 const UChar *end = data() + size();
00797 for (const UChar *c = data() + pos; c < end; c++)
00798 if (*c == ch)
00799 return (c-data());
00800
00801 return -1;
00802 }
00803
00804 int UString::rfind(const UString &f, int pos) const
00805 {
00806 int sz = size();
00807 int fsz = f.size();
00808 if (sz < fsz)
00809 return -1;
00810 if (pos < 0)
00811 pos = 0;
00812 if (pos > sz - fsz)
00813 pos = sz - fsz;
00814 if (fsz == 0)
00815 return pos;
00816 long fsizeminusone = (fsz - 1) * sizeof(UChar);
00817 const UChar *fdata = f.data();
00818 for (const UChar *c = data() + pos; c >= data(); c--) {
00819 if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone))
00820 return (c-data());
00821 }
00822
00823 return -1;
00824 }
00825
00826 int UString::rfind(UChar ch, int pos) const
00827 {
00828 if (isEmpty())
00829 return -1;
00830 if (pos + 1 >= size())
00831 pos = size() - 1;
00832 for (const UChar *c = data() + pos; c >= data(); c--) {
00833 if (*c == ch)
00834 return (c-data());
00835 }
00836
00837 return -1;
00838 }
00839
00840 UString UString::substr(int pos, int len) const
00841 {
00842 if (pos < 0)
00843 pos = 0;
00844 else if (pos >= (int) size())
00845 pos = size();
00846 if (len < 0)
00847 len = size();
00848 if (pos + len >= (int) size())
00849 len = size() - pos;
00850
00851 UChar *tmp = allocateChars(len);
00852 memcpy(tmp, data()+pos, len * sizeof(UChar));
00853 UString result(tmp, len);
00854 delete [] tmp;
00855
00856 return result;
00857 }
00858
00859 void UString::attach(Rep *r)
00860 {
00861 rep = r;
00862 rep->ref();
00863 }
00864
00865 void UString::detach()
00866 {
00867 if (rep->rc > 1) {
00868 int l = size();
00869 UChar *n = allocateChars(l);
00870 memcpy(n, data(), l * sizeof(UChar));
00871 release();
00872 rep = Rep::create(n, l);
00873 }
00874 }
00875
00876 void UString::release()
00877 {
00878 rep->deref();
00879 }
00880
00881 bool KJS::operator==(const UString& s1, const UString& s2)
00882 {
00883 if (s1.rep->len != s2.rep->len)
00884 return false;
00885
00886 return (memcmp(s1.rep->dat, s2.rep->dat,
00887 s1.rep->len * sizeof(UChar)) == 0);
00888 }
00889
00890 bool KJS::operator==(const UString& s1, const char *s2)
00891 {
00892 if (s2 == 0) {
00893 return s1.isEmpty();
00894 }
00895
00896 const UChar *u = s1.data();
00897 const UChar *uend = u + s1.size();
00898 while (u != uend && *s2) {
00899 if (u->uc != (unsigned char)*s2)
00900 return false;
00901 s2++;
00902 u++;
00903 }
00904
00905 return u == uend && *s2 == 0;
00906 }
00907
00908 bool KJS::operator<(const UString& s1, const UString& s2)
00909 {
00910 const int l1 = s1.size();
00911 const int l2 = s2.size();
00912 const int lmin = l1 < l2 ? l1 : l2;
00913 const UChar *c1 = s1.data();
00914 const UChar *c2 = s2.data();
00915 int l = 0;
00916 while (l < lmin && *c1 == *c2) {
00917 c1++;
00918 c2++;
00919 l++;
00920 }
00921 if (l < lmin)
00922 return (c1->uc < c2->uc);
00923
00924 return (l1 < l2);
00925 }
00926
00927 int KJS::compare(const UString& s1, const UString& s2)
00928 {
00929 const int l1 = s1.size();
00930 const int l2 = s2.size();
00931 const int lmin = l1 < l2 ? l1 : l2;
00932 const UChar *c1 = s1.data();
00933 const UChar *c2 = s2.data();
00934 int l = 0;
00935 while (l < lmin && *c1 == *c2) {
00936 c1++;
00937 c2++;
00938 l++;
00939 }
00940 if (l < lmin)
00941 return (c1->uc > c2->uc) ? 1 : -1;
00942
00943 if (l1 == l2) {
00944 return 0;
00945 }
00946 return (l1 < l2) ? 1 : -1;
00947 }