1 // -*- c-basic-offset: 2 -*-
2 /*
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the Library GNU General Public
5 version 2 of the License, or (at your option) version 3 or,
6 at the discretion of KDE e.V (which shall act as a proxy as in
7 section 14 of the GPLv3), any later version..
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 #include "ustring.h"
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #endif
32 #ifdef HAVE_STRINGS_H
33 #include <strings.h>
34 #endif
35
36 #ifdef HAVE_MATH_H
37 #include <math.h>
38 #endif
39 #ifdef HAVE_FLOAT_H
40 #include <float.h>
41 #endif
42 #ifdef HAVE_IEEEFP_H
43 #include <ieeefp.h>
44 #endif
45
46 namespace wvWare {
47 #ifdef WORDS_BIGENDIAN
48 const unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
49 const unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
50 #elif defined(arm)
51 const unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
52 const unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
53 #else
54 const unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
55 const unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
56 #endif
57
58 const double NaN = *( reinterpret_cast<const double*>( NaN_Bytes ) );
59 const double Inf = *( reinterpret_cast<const double*>( Inf_Bytes ) );
60 }
61
62 using namespace wvWare;
63
isNaN(double d)64 bool wvWare::isNaN(double d)
65 {
66 #ifdef HAVE_FUNC_ISNAN
67 return isnan(d);
68 #elif defined HAVE_FLOAT_H
69 return _isnan(d) != 0;
70 #else
71 // IEEE: NaN != NaN
72 return !(d == d);
73 #endif
74 }
75
isPosInf(double d)76 bool wvWare::isPosInf(double d)
77 {
78 #if defined(HAVE_FUNC_ISINF)
79 return (isinf(d) == 1);
80 #elif defined(HAVE_FUNC_ISFINITE)
81 return isfinite(d) == 0 && d == d; // ### can we distinguish between + and - ?
82 #elif defined(HAVE_FUNC_FINITE)
83 return finite(d) == 0 && d == d; // ### can we distinguish between + and - ?
84 #elif defined(HAVE_FUNC__FINITE)
85 return _finite(d) == 0 && d == d; // ###
86 #else
87 return false;
88 #endif
89 }
90
isNegInf(double d)91 bool wvWare::isNegInf(double d)
92 {
93 #if defined(HAVE_FUNC_ISINF)
94 return (isinf(d) == -1);
95 #elif defined(HAVE_FUNC_ISFINITE)
96 return isfinite(d) == 0 && d == d; // ###
97 #elif defined(HAVE_FUNC_FINITE)
98 return finite(d) == 0 && d == d; // ###
99 #elif defined(HAVE_FUNC__FINITE)
100 return _finite(d) == 0 && d == d; // ###
101 #else
102 return false;
103 #endif
104 }
105
CString(const char * c)106 CString::CString(const char *c)
107 {
108 data = new char[strlen(c)+1];
109 strcpy(data, c);
110 }
111
CString(const CString & b)112 CString::CString(const CString &b)
113 {
114 data = new char[b.length()+1];
115 strcpy(data, b.c_str());
116 }
117
~CString()118 CString::~CString()
119 {
120 delete [] data;
121 }
122
append(const CString & t)123 CString &CString::append(const CString &t)
124 {
125 char *n;
126 if (data) {
127 n = new char[strlen(data)+t.length()+1];
128 strcpy(n, data);
129 } else {
130 n = new char[t.length()+1];
131 n[0] = '\0';
132 }
133 strcat(n, t.c_str());
134
135 delete [] data;
136 data = n;
137
138 return *this;
139 }
140
operator =(const char * c)141 CString &CString::operator=(const char *c)
142 {
143 if (data)
144 delete [] data;
145 data = new char[strlen(c)+1];
146 strcpy(data, c);
147
148 return *this;
149 }
150
operator =(const CString & str)151 CString &CString::operator=(const CString &str)
152 {
153 if (this == &str)
154 return *this;
155
156 if (data)
157 delete [] data;
158 data = new char[str.length()+1];
159 strcpy(data, str.c_str());
160
161 return *this;
162 }
163
operator +=(const CString & str)164 CString &CString::operator+=(const CString &str)
165 {
166 return append(CString(str.c_str()));
167 }
168
length() const169 int CString::length() const
170 {
171 return strlen(data);
172 }
173
operator ==(const wvWare::CString & c1,const wvWare::CString & c2)174 bool wvWare::operator==(const wvWare::CString& c1, const wvWare::CString& c2)
175 {
176 return (strcmp(c1.c_str(), c2.c_str()) == 0);
177 }
178
179 UChar UChar::null;
180 UString::Rep UString::Rep::null = { 0, 0, 1 };
181 UString UString::null;
182 static char *statBuffer = 0L;
183
UChar(const UCharReference & c)184 UChar::UChar(const UCharReference &c)
185 : uc( c.unicode() )
186 {
187 }
188
toLower() const189 UChar UChar::toLower() const
190 {
191 // ### properly support unicode tolower
192 if (uc >= 256 || islower(uc))
193 return *this;
194
195 return UChar(tolower(uc));
196 }
197
toUpper() const198 UChar UChar::toUpper() const
199 {
200 if (uc >= 256 || isupper(uc))
201 return *this;
202
203 return UChar(toupper(uc));
204 }
205
operator =(UChar c)206 UCharReference& UCharReference::operator=(UChar c)
207 {
208 str->detach();
209 if (offset < str->rep->len)
210 *(str->rep->dat + offset) = c;
211 /* TODO: lengthen string ? */
212 return *this;
213 }
214
ref() const215 UChar& UCharReference::ref() const
216 {
217 if (offset < str->rep->len)
218 return *(str->rep->dat + offset);
219 else
220 return UChar::null;
221 }
222
223 namespace {
224 // return an uninitialized UChar array of size s
allocateChars(int s)225 static inline UChar* allocateChars(int s)
226 {
227 // work around default UChar constructor code
228 return reinterpret_cast<UChar*>(new short[s]);
229 }
230 }
231
create(UChar * d,int l)232 UString::Rep *UString::Rep::create(UChar *d, int l)
233 {
234 Rep *r = new Rep;
235 r->dat = d;
236 r->len = l;
237 r->rc = 1;
238
239 return r;
240 }
241
UString()242 UString::UString()
243 {
244 null.rep = &Rep::null;
245 attach(&Rep::null);
246 }
247
UString(char c)248 UString::UString(char c)
249 {
250 UChar *d = allocateChars( 1 );
251 d[0] = UChar(0, c);
252 rep = Rep::create(d, 1);
253 }
254
UString(UChar c)255 UString::UString(UChar c)
256 {
257 UChar *d = allocateChars( 1 );
258 d[0] = c;
259 rep = Rep::create(d, 1);
260 }
261
UString(const char * c)262 UString::UString(const char *c)
263 {
264 attach(&Rep::null);
265 operator=(c);
266 }
267
UString(const UChar * c,int length)268 UString::UString(const UChar *c, int length)
269 {
270 UChar *d = allocateChars( length );
271 memcpy(d, c, length * sizeof(UChar));
272 rep = Rep::create(d, length);
273 }
274
UString(UChar * c,int length,bool copy)275 UString::UString(UChar *c, int length, bool copy)
276 {
277 UChar *d;
278 if (copy) {
279 d = allocateChars( length );
280 memcpy(d, c, length * sizeof(UChar));
281 } else
282 d = c;
283 rep = Rep::create(d, length);
284 }
285
UString(const UString & b)286 UString::UString(const UString &b)
287 {
288 attach(b.rep);
289 }
290
~UString()291 UString::~UString()
292 {
293 release();
294 }
295
from(int i)296 UString UString::from(int i)
297 {
298 char buf[40];
299 sprintf(buf, "%d", i);
300
301 return UString(buf);
302 }
303
from(unsigned int u)304 UString UString::from(unsigned int u)
305 {
306 char buf[40];
307 sprintf(buf, "%u", u);
308
309 return UString(buf);
310 }
311
from(double d)312 UString UString::from(double d)
313 {
314 char buf[40];
315
316 if (d == -0)
317 strcpy(buf,"0");
318 else if (isNaN(d))
319 strcpy(buf,"NaN");
320 else if (isPosInf(d))
321 strcpy(buf,"Infinity");
322 else if (isNegInf(d))
323 strcpy(buf,"-Infinity");
324 else
325 sprintf(buf, "%.16g", d); // does the right thing
326
327 // ECMA 3rd ed. 9.8.1 9 e: "with no leading zeros"
328 int buflen = strlen(buf);
329 if (buflen >= 4 && buf[buflen-4] == 'e' && buf[buflen-2] == '0') {
330 buf[buflen-2] = buf[buflen-1];
331 buf[buflen-1] = 0;
332 }
333
334 return UString(buf);
335 }
336
append(const UString & t)337 UString &UString::append(const UString &t)
338 {
339 int l = length();
340 UChar *n = allocateChars( l+t.length() );
341 memcpy(n, data(), l * sizeof(UChar));
342 memcpy(n+l, t.data(), t.length() * sizeof(UChar));
343 release();
344 rep = Rep::create(n, l + t.length());
345
346 return *this;
347 }
348
cstring() const349 CString UString::cstring() const
350 {
351 return CString(ascii());
352 }
353
ascii() const354 char *UString::ascii() const
355 {
356 if (statBuffer)
357 delete [] statBuffer;
358
359 statBuffer = new char[length()+1];
360 for(int i = 0; i < length(); i++)
361 statBuffer[i] = data()[i].low();
362 statBuffer[length()] = '\0';
363
364 return statBuffer;
365 }
366
operator =(const char * c)367 UString &UString::operator=(const char *c)
368 {
369 release();
370 int l = c ? strlen(c) : 0;
371 UChar *d = allocateChars( l );
372 for (int i = 0; i < l; i++)
373 d[i].uc = static_cast<unsigned char>( c[i] );
374 rep = Rep::create(d, l);
375
376 return *this;
377 }
378
operator =(const UString & str)379 UString &UString::operator=(const UString &str)
380 {
381 str.rep->ref();
382 release();
383 rep=str.rep;
384
385 return *this;
386 }
387
operator +=(const UString & s)388 UString &UString::operator+=(const UString &s)
389 {
390 return append(s);
391 }
392
is8Bit() const393 bool UString::is8Bit() const
394 {
395 const UChar *u = data();
396 for(int i = 0; i < length(); i++, u++)
397 if (u->uc > 0xFF)
398 return false;
399
400 return true;
401 }
402
operator [](int pos) const403 UChar UString::operator[](int pos) const
404 {
405 if (pos >= length())
406 return UChar::null;
407
408 return static_cast<const UChar *>( data() )[pos];
409 }
410
operator [](int pos)411 UCharReference UString::operator[](int pos)
412 {
413 /* TODO: boundary check */
414 return UCharReference(this, pos);
415 }
416
toDouble(bool tolerant) const417 double UString::toDouble( bool tolerant ) const
418 {
419 double d;
420
421 if (!is8Bit())
422 return NaN;
423
424 CString str = cstring();
425 const char *c = str.c_str();
426
427 // skip leading white space
428 while (isspace(*c))
429 c++;
430
431 // empty string ?
432 if (*c == '\0')
433 return tolerant ? NaN : 0.0;
434
435 // hex number ?
436 if (*c == '0' && (*(c+1) == 'x' || *(c+1) == 'X')) {
437 c++;
438 d = 0.0;
439 while (*(++c)) {
440 if (*c >= '0' && *c <= '9')
441 d = d * 16.0 + *c - '0';
442 else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f'))
443 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
444 else
445 break;
446 }
447 } else {
448 // regular number ?
449 char *end;
450 d = strtod(c, &end);
451 if ((d != 0.0 || end != c) && d != HUGE_VAL && d != -HUGE_VAL) {
452 c = end;
453 } else {
454 // infinity ?
455 d = 1.0;
456 if (*c == '+')
457 c++;
458 else if (*c == '-') {
459 d = -1.0;
460 c++;
461 }
462 if (strncmp(c, "Infinity", 8) != 0)
463 return NaN;
464 d = d * Inf;
465 c += 8;
466 }
467 }
468
469 // allow trailing white space
470 while (isspace(*c))
471 c++;
472 // don't allow anything after - unless tolerant=true
473 if ( !tolerant && *c != '\0')
474 d = NaN;
475
476 return d;
477 }
478
toULong(bool * ok) const479 unsigned long UString::toULong(bool *ok) const
480 {
481 double d = toDouble();
482 bool b = true;
483
484 if (isNaN(d) || d != static_cast<unsigned long>(d)) {
485 b = false;
486 d = 0;
487 }
488
489 if (ok)
490 *ok = b;
491
492 return static_cast<unsigned long>(d);
493 }
494
find(const UString & f,int pos) const495 int UString::find(const UString &f, int pos) const
496 {
497 if (isNull())
498 return -1;
499 long fsize = f.length() * sizeof(UChar);
500 if (pos < 0)
501 pos = 0;
502 const UChar *end = data() + length() - f.length();
503 for (const UChar *c = data() + pos; c <= end; c++)
504 if (!memcmp(c, f.data(), fsize))
505 return (c-data());
506
507 return -1;
508 }
509
rfind(const UString & f,int pos) const510 int UString::rfind(const UString &f, int pos) const
511 {
512 if (isNull())
513 return -1;
514 if (pos + f.length() >= length())
515 pos = length() - f.length();
516 long fsize = f.length() * sizeof(UChar);
517 for (const UChar *c = data() + pos; c >= data(); c--) {
518 if (!memcmp(c, f.data(), fsize))
519 return (c-data());
520 }
521
522 return -1;
523 }
524
substr(int pos,int len) const525 UString UString::substr(int pos, int len) const
526 {
527 if (isNull())
528 return UString();
529 if (pos < 0)
530 pos = 0;
531 else if (pos >= static_cast<int>( length() ))
532 pos = length();
533 if (len < 0)
534 len = length();
535 if (pos + len >= static_cast<int>( length() ))
536 len = length() - pos;
537
538 UChar *tmp = allocateChars( len );
539 memcpy(tmp, data()+pos, len * sizeof(UChar));
540 UString result(tmp, len);
541 delete [] tmp;
542
543 return result;
544 }
545
attach(Rep * r)546 void UString::attach(Rep *r)
547 {
548 rep = r;
549 rep->ref();
550 }
551
detach()552 void UString::detach()
553 {
554 if (rep->rc > 1) {
555 int l = length();
556 UChar *n = allocateChars( l );
557 memcpy(n, data(), l * sizeof(UChar));
558 release();
559 rep = Rep::create(n, l);
560 }
561 }
562
release()563 void UString::release()
564 {
565 if (!rep->deref()) {
566 delete [] rep->dat;
567 delete rep;
568 }
569 }
570
operator ==(const UString & s1,const UString & s2)571 bool wvWare::operator==(const UString& s1, const UString& s2)
572 {
573 if (s1.rep->len != s2.rep->len)
574 return false;
575
576 return (memcmp(s1.rep->dat, s2.rep->dat,
577 s1.rep->len * sizeof(UChar)) == 0);
578 }
579
operator ==(const UString & s1,const char * s2)580 bool wvWare::operator==(const UString& s1, const char *s2)
581 {
582 if (s2 == 0L && s1.isNull())
583 return true;
584
585 if (s1.length() != static_cast<int>( strlen(s2) ))
586 return false;
587
588 const UChar *u = s1.data();
589 while (*s2) {
590 if (u->uc != *s2 )
591 return false;
592 s2++;
593 u++;
594 }
595
596 return true;
597 }
598
operator <(const UString & s1,const UString & s2)599 bool wvWare::operator<(const UString& s1, const UString& s2)
600 {
601 const int l1 = s1.length();
602 const int l2 = s2.length();
603 const int lmin = l1 < l2 ? l1 : l2;
604 const UChar *c1 = s1.data();
605 const UChar *c2 = s2.data();
606 int l = 0;
607 while (l < lmin && *c1 == *c2) {
608 c1++;
609 c2++;
610 l++;
611 }
612 if (l < lmin)
613 return (c1->unicode() < c2->unicode());
614
615 return (l1 < l2);
616 }
617
operator +(const UString & s1,const UString & s2)618 UString wvWare::operator+(const UString& s1, const UString& s2)
619 {
620 UString tmp(s1);
621 tmp.append(s2);
622
623 return tmp;
624 }
625
626
UConstString(UChar * data,unsigned int length)627 UConstString::UConstString( UChar* data, unsigned int length ) : UString( data, length, false )
628 {
629 }
630
~UConstString()631 UConstString::~UConstString()
632 {
633 if ( rep->rc > 1 ) {
634 int l = length();
635 UChar* n = allocateChars( l );
636 memcpy( n, data(), l * sizeof( UChar ) );
637 rep->dat = n;
638 }
639 else
640 rep->dat = 0;
641 }
642