kspread/excel/sidewinder/ustring.cpp
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
4 * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22#include "ustring.h"
23
24#include <string.h>
25#include <ctype.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <math.h>
29
30#ifdef _MSC_VER
31#define snprintf _snprintf
32#endif
33
34using namespace Swinder;
35
37UString::Rep UString::Rep::null = { 0, 0, 1, 0 };
39static char *statBuffer = 0L;
40
42 : uc( c.unicode() )
43{
44}
45
47{
48 str->detach();
49 if (offset < str->rep->len)
50 *(str->rep->dat + offset) = c;
51 /* TODO: lengthen string ? */
52 return *this;
53}
54
55UChar& UCharReference::ref() const
56{
57 if (offset < str->rep->len)
58 return *(str->rep->dat + offset);
59 else
60 {
61 static UChar nullRef('\0');
62 return nullRef;
63 }
64}
65
66namespace {
67 // return an uninitialized UChar array of size s
68 static inline UChar* allocateChars(int s)
69 {
70 // work around default UChar constructor code
71 return reinterpret_cast<UChar*>(new short[s]);
72 }
73}
74
75
76UString::Rep *UString::Rep::create(UChar *d, int l)
77{
78 Rep *r = new Rep;
79 r->dat = d;
80 r->len = l;
81 r->cap = l;
82 r->rc = 1;
83
84 return r;
85}
86
87UString::Rep *UString::Rep::create(UChar *d, int l, int c)
88{
89 Rep *r = new Rep;
90 r->dat = d;
91 r->len = l;
92 r->cap = c;
93 r->rc = 1;
94
95 return r;
96}
97
99{
100 null.rep = &Rep::null;
101 attach(&Rep::null);
102}
103
105{
106 UChar *d = allocateChars( 1 );
107 d[0] = UChar(0, c);
108 rep = Rep::create(d, 1);
109}
110
112{
113 UChar *d = allocateChars( 1 );
114 d[0] = c;
115 rep = Rep::create(d, 1);
116}
117
118UString::UString(const char *c)
119{
120 attach(&Rep::null);
121 operator=(c);
122}
123
124UString::UString(const UChar *c, int length)
125{
126 UChar *d = allocateChars( length );
127 memcpy(d, c, length * sizeof(UChar));
128 rep = Rep::create(d, length);
129}
130
131UString::UString(UChar *c, int length, bool copy)
132{
133 UChar *d;
134 if (copy) {
135 d = allocateChars( length );
136 memcpy(d, c, length * sizeof(UChar));
137 } else
138 d = c;
139 rep = Rep::create(d, length);
140}
141
143{
144 attach(b.rep);
145}
146
147// NOTE: this is private, be careful when using it !
148UString::UString(Rep *r): rep(r)
149{
150}
151
152
154{
155 release();
156}
157
159{
160#if 0
161 // standard and safe way
162 char buf[1+sizeof(int)*3];
163 snprintf(buf, sizeof(int)*3, "%d", i);
164 buf[sizeof(int)*3] = '\0';
165 return UString(buf);
166#else
167 // micro-optimized version
168 static unsigned short digits[] =
169 { '9', '8', '7', '6', '5', '4', '3', '2', '1',
170 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
171
172 UString::Rep* rep = 0;
173
174 if(i == 0)
175 {
176 UChar* buf = allocateChars(1);
177 buf[0] = '0';
178 rep = Rep::create(buf, 1);
179 }
180 else
181 {
182 bool neg = (i < 0);
183 int ndig = 1 + sizeof(int)*3;
184
185 UChar* buf = allocateChars(ndig);
186 UChar* ptr = buf + ndig - 1;
187 int len = (neg) ? 1 : 0;
188
189 // construct all the digits
190 for(; i != 0; i/=10, len++)
191 *ptr-- = digits[9+i%10];
192
193 if(neg)
194 *ptr-- = '-';
195
196 // shift, don't use memcpy because overlapping area
197 memmove(buf, ptr+1, len*sizeof(unsigned short));
198
199 rep = Rep::create(buf, len, ndig);
200 }
201
202 return UString(rep);
203#endif
204}
205
207{
208#if 0
209 // standard and safe way
210 char buf[1+sizeof(unsigned int)*3];
211 snprintf(buf, sizeof(unsigned int)*3, "%d", u);
212 buf[sizeof(int)*3] = '\0';
213 return UString(buf);
214#else
215 // micro-optimized version
216 static unsigned short digits[] =
217 { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
218
219 UString::Rep* rep = 0;
220
221 if(u < 10)
222 {
223 UChar* buf = allocateChars(1);
224 buf[0] = digits[u];
225 rep = Rep::create(buf, 1);
226 }
227 else
228 {
229 int ndig = 1 + sizeof(int)*3;
230 UChar* buf = allocateChars(ndig);
231 UChar* ptr = buf + ndig - 1;
232 int len = 0;
233
234 // construct all the digits
235 for(; u != 0; u/=10, len++)
236 *ptr-- = digits[u%10];
237
238 // shift, don't use memcpy because overlapping area
239 memmove(buf, ptr+1, len*sizeof(unsigned short));
240
241 rep = Rep::create(buf, len, ndig);
242 }
243
244 return UString(rep);
245#endif
246}
247
249{
250 char buf[40];
251 snprintf(buf, 39, "%.16g", d);
252 buf[sizeof(int)*3] = '\0';
253 return UString(buf);
254}
255
257{
258 if((n >= 0) && (n < length()))
259 {
260 detach();
261 rep->len = n;
262 }
263}
264
266{
267 if(r > length())
268 {
269 int l = length();
270 UChar* n = allocateChars( r );
271 memcpy(n, data(), l * sizeof(UChar));
272 release();
273 rep = Rep::create(n, l, r);
274 }
275}
276
278{
279 int tl = t.length();
280 if(tl > 0)
281 {
282 detach();
283 int l = length();
284
285 // no space, we have to reallocate first
286 if(capacity() < tl + l)
287 reserve(tl +l);
288
289 UChar *dd = rep->data();
290 memcpy(dd+l, t.data(), tl * sizeof(UChar));
291 rep->len += tl;
292 }
293
294 return *this;
295}
296
298{
299 int tl = strlen(s);
300 if(tl > 0)
301 {
302 detach();
303 int l = length();
304
305 // no space, we have to reallocate first
306 if(capacity() < tl + l)
307 reserve(tl +l);
308
309 // copy each character
310 UChar *dd = rep->data();
311 for (int i = 0; i < tl; i++)
312 dd[l+i].uc = static_cast<unsigned char>( s[i] );
313 rep->len += tl;
314 }
315
316 return *this;
317}
318
320{
321 detach();
322 int l = length();
323
324 // we need to reallocate
325 // in case another append follows, so let's reserve()
326 // this avoids subsequent expensive reallocation
327 if(capacity() < l + 1)
328 reserve(l + 8);
329
330 UChar *dd = rep->data();
331 dd[l] = c;
332 rep->len++;
333
334 return *this;
335}
336
338{
339 return append( UChar((unsigned short)c) );
340}
341
342
344{
345 int tl = t.length();
346 if(tl > 0)
347 {
348 int l = length();
349
350 // no space, we have to reallocate first
351 if(capacity() < tl + l)
352 reserve(tl +l);
353
354 // shift the string, then place the new string
355 UChar *dd = rep->data();
356 for(int i = l-1; i >= 0; i--)
357 dd[i+tl] = dd[i];
358 memcpy(dd, t.data(), tl * sizeof(UChar));
359 rep->len += tl;
360 }
361
362 return *this;
363}
364
366{
367 int tl = strlen(s);
368 if(tl > 0)
369 {
370 int l = length();
371
372 // no space, we have to reallocate first
373 if(capacity() < tl + l)
374 reserve(tl +l);
375
376 // shift the string, then copy each new character
377 UChar *dd = rep->data();
378 for(int i = l-1; i >= 0; i--)
379 dd[i+tl] = dd[i];
380 for(int j = 0; j < tl; j++)
381 dd[j].uc = static_cast<unsigned char>( s[j] );
382 rep->len += tl;
383 }
384
385 return *this;
386}
387
389{
390 int l = length();
391
392 // we need to reallocate and reserve
393 // see also append(UChar c) function
394 if(capacity() < l + 1)
395 reserve(l + 8);
396
397 UChar *dd = rep->data();
398 for(int i = l-1; i >= 0; i--)
399 dd[i+1] = dd[i];
400 dd[0] = c;
401 rep->len++;
402
403 return *this;
404}
405
407{
408 return prepend( UChar((unsigned short)c) );
409}
410
411char *UString::ascii() const
412{
413 if (statBuffer)
414 delete [] statBuffer;
415
416 statBuffer = new char[length()+1];
417 for(int i = 0; i < length(); i++)
418 statBuffer[i] = data()[i].low();
419 statBuffer[length()] = '\0';
420
421 return statBuffer;
422}
423
425{
426 release();
427 int l = c ? strlen(c) : 0;
428 UChar *d = allocateChars( l );
429 for (int i = 0; i < l; i++)
430 d[i].uc = static_cast<unsigned char>( c[i] );
431 rep = Rep::create(d, l);
432
433 return *this;
434}
435
437{
438 str.rep->ref();
439 release();
440 rep=str.rep;
441
442 return *this;
443}
444
446{
447 return append(s);
448}
449
450bool UString::is8Bit() const
451{
452 const UChar *u = data();
453 for(int i = 0; i < length(); i++, u++)
454 if (u->uc > 0xFF)
455 return false;
456
457 return true;
458}
459
461{
462 if (pos >= length())
463 return UChar::null;
464
465 return static_cast<const UChar *>( data() )[pos];
466}
467
469{
470 /* TODO: boundary check */
471 return UCharReference(this, pos);
472}
473
474UString UString::substr(int pos, int len) const
475{
476 if (isNull())
477 return UString();
478 if (pos < 0)
479 pos = 0;
480 else if (pos >= static_cast<int>( length() ))
481 pos = length();
482 if (len < 0)
483 len = length();
484 if (pos + len >= static_cast<int>( length() ))
485 len = length() - pos;
486
487 UChar *tmp = allocateChars( len );
488 memcpy(tmp, data()+pos, len * sizeof(UChar));
489 UString result(tmp, len);
490 delete [] tmp;
491
492 return result;
493}
494
495int 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
510void UString::attach(Rep *r)
511{
512 rep = r;
513 rep->ref();
514}
515
516void UString::detach()
517{
518 if (rep->rc > 1)
519 {
520 int c = capacity();
521 int l = length();
522 UChar *n = allocateChars( c );
523 memcpy(n, data(), l * sizeof(UChar));
524 release();
525 rep = Rep::create(n, l, c);
526 }
527}
528
529void UString::release()
530{
531 if (!rep->deref())
532 {
533 delete [] rep->dat;
534 delete rep;
535 }
536}
537
538bool Swinder::operator==(const UString& s1, const UString& s2)
539{
540 if (s1.rep->len != s2.rep->len)
541 return false;
542
543 return (memcmp(s1.rep->dat, s2.rep->dat,
544 s1.rep->len * sizeof(UChar)) == 0);
545}
546
547bool Swinder::operator==(const UString& s1, const char *s2)
548{
549 if (s2 == 0L)
550 return s1.isEmpty();
551
552 if (s1.length() != static_cast<int>( strlen(s2) ))
553 return false;
554
555 const UChar *u = s1.data();
556 while (*s2)
557 {
558 if (u->uc != *s2 )
559 return false;
560 s2++;
561 u++;
562 }
563
564 return true;
565}
566
567bool Swinder::operator<(const UString& s1, const UString& s2)
568{
569 const int l1 = s1.length();
570 const int l2 = s2.length();
571 const int lmin = l1 < l2 ? l1 : l2;
572 const UChar *c1 = s1.data();
573 const UChar *c2 = s2.data();
574 int l = 0;
575 while (l < lmin && *c1 == *c2)
576 {
577 c1++;
578 c2++;
579 l++;
580 }
581 if (l < lmin)
582 return (c1->unicode() < c2->unicode());
583
584 return (l1 < l2);
585}
586
587UString Swinder::operator+(const UString& s1, const UString& s2)
588{
589 UString tmp(s1);
590 tmp.append(s2);
591
592 return tmp;
593}
594
595
596UConstString::UConstString( UChar* data, unsigned int length ) :
597UString( data, length, false )
598{
599}
600
601UConstString::~UConstString()
602{
603 if ( rep->rc > 1 ) {
604 int l = length();
605 UChar* n = allocateChars( l );
606 memcpy( n, data(), l * sizeof( UChar ) );
607 rep->dat = n;
608 }
609 else
610 rep->dat = 0;
611}
Dynamic reference to a string character.
UCharReference & operator=(UChar c)
Set the referenced character to c.
bool is8Bit() const
Use this if you want to make sure that this string is a plain ASCII string.
UString & prepend(const UString &)
Prepend another string.
int find(const UString &f, int pos=0) const
static UString number(int i)
Constructs a string from an int.
UString()
Constructs a null string.
UString & operator=(const char *c)
Assignment operator.
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
UString & operator+=(const UString &s)
Appends the specified string.
void truncate(int n)
Truncates the string to n.
static UString null
Static instance of a null string.
UString substr(int pos=0, int len=-1) const
void reserve(int r)
Reserves room for the string, useful to speed up append().
UChar operator[](int pos) const
Const character at specified position.
UString & append(const UString &)
Append another string.
static UChar null
A static instance of UChar(0).
UChar()
Construct a character with value 0.
unsigned short unicode() const