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