blob: 78e863cc9c09d60f9022bf79fd6336921f909e44 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program 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
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <cc++/config.h>
40#include <cc++/export.h>
41#include <cc++/thread.h>
42#include <cc++/misc.h>
43#include <cc++/strchar.h>
44#include <cc++/string.h>
45#include "private.h"
46
47#ifdef __BORLANDC__
48#include <stdarg.h>
49#include <stdio.h>
50#include <stdlib.h>
51#else
52#include <cstdarg>
53#include <cstdio>
54#include <cstdlib>
55#endif
56
57#ifdef CCXX_NAMESPACES
58namespace ost {
59using std::streambuf;
60using std::ofstream;
61using std::ostream;
62using std::endl;
63using std::ios;
64#endif
65
66static Mutex mutex;
67MemPager *String::pager = NULL;
68char **String::idx = NULL;
69
70const unsigned String::minsize = ((sizeof(char *) + (sizeof(unsigned) * 2) + 1));
71const unsigned String::slotsize = 32;
72const unsigned String::pagesize = 1024;
73const unsigned String::slotlimit = 512;
74const unsigned String::slotcount = ((slotlimit / slotsize) + 1);
75const size_t String::npos = (size_t)(-1);
76
77String::String()
78{
79 init();
80}
81
82String::String(std::string str)
83{
84 init();
85 set(str.c_str());
86}
87
88String::String(const String &original)
89{
90 init();
91 copy(original);
92}
93
94String::String(size_t chars, const char chr)
95{
96 init();
97 resize(chars + 1);
98 memset(getText(), chr, chars);
99 setLength(chars);
100}
101
102#ifdef HAVE_SNPRINTF
103String::String(size_t chars, const char *format, ...)
104{
105 va_list args;
106 va_start(args, format);
107
108 init();
109 resize(chars);
110
111 char *ptr = getText();
112 vsnprintf(ptr, chars, format, args);
113 setLength(strlen(ptr));
114 va_end(args);
115}
116#else
117String::String(size_t chars, const char *str)
118{
119 init();
120 resize(chars);
121
122 if(!str || !*str)
123 return;
124
125 set(str);
126}
127#endif
128
129String::String(const char *str)
130{
131 init();
132 set(str);
133}
134
135String::String(const String &str, size_t start, size_t chars)
136{
137 init();
138 char *ptr = str.getText();
139 size_t len = str.getLength();
140
141 if(start >= len)
142 return;
143
144 ptr += start;
145 len -= start;
146
147 if(chars >= len)
148 chars = len;
149
150 set(ptr, chars);
151}
152
153char String::at(ssize_t ind) const
154{
155 if(ind < 0)
156 ind = (ssize_t)(getLength() - ind + 1);
157 if((size_t)ind > getLength() || ind < 0)
158 return 0;
159
160 return (getText())[ind];
161}
162
163void String::insert(size_t start, const char *str, size_t chars)
164{
165 char *ptr = getText();
166 size_t len = getLength();
167 size_t sz = getSize();
168
169 if(!str)
170 str = "";
171
172 if(!chars)
173 chars = strlen(str);
174
175 if(!chars || start > len)
176 return;
177
178 if(len + chars >= sz) {
179 resize(len + chars + 1);
180 ptr = getText();
181 }
182
183 if(start == len) {
184 memmove(ptr + start, str, chars);
185 len += chars;
186 setLength(len);
187 ptr[len] = 0;
188 return;
189 }
190
191 memmove(ptr + start + chars, ptr + start, len - start);
192 memmove(ptr + start, str, chars);
193 len += chars;
194 setLength(len);
195 ptr[len] = 0;
196 return;
197}
198
199
200void String::insert(size_t start, const String &s)
201{
202 insert(start, s.getText(), s.getLength());
203}
204
205void String::replace(size_t start, size_t len, const char *cp, size_t chars)
206{
207 erase(start, len);
208 insert(start, cp, chars);
209}
210
211void String::replace(size_t start, size_t len, const String &s)
212{
213 erase(start, len);
214 insert(start, s);
215}
216
217void String::erase(size_t start, size_t chars)
218{
219 size_t len = getLength();
220 char *ptr = getText();
221
222 if(start >= len)
223 return;
224
225 if(start + chars >= len || chars == npos || !chars) {
226 setLength(start);
227 ptr[start] = 0;
228 return;
229 }
230
231 memmove(ptr + start, ptr + start + chars, len - start - chars);
232 len -= chars;
233 setLength(len);
234 ptr[len] = 0;
235}
236
237void String::append(const char *str, size_t offset, size_t len)
238{
239 size_t slen = getLength();
240 char *ptr = getText();
241
242 if(slen < offset) {
243 append(str, len);
244 return;
245 }
246
247 setLength(offset);
248 ptr[offset] = 0;
249 append(str, len);
250}
251
252void String::append(const char *str, size_t len)
253{
254 if(!str)
255 return;
256
257 if(!len)
258 len = strlen(str);
259
260 if(!len)
261 return;
262
263 if(getLength() + len >= getSize())
264 resize(getLength() + len + 1);
265 memmove(getText() + getLength(), str, len);
266 len += getLength();
267 setLength(len);
268 getText()[len] = 0;
269 return;
270}
271
272void String::add(char c)
273{
274 size_t len = getLength();
275 char *ptr;
276
277 if(len + 1 >= getSize())
278 resize(len + 2);
279
280 ptr = getText();
281 ptr[len++] = c;
282 setLength(len);
283 ptr[len] = 0;
284}
285
286void String::trim(size_t chars)
287{
288 size_t len = getLength();
289 char *ptr = getText();
290
291 if(chars >= len)
292 chars = len;
293
294 len -= chars;
295 ptr[len] = 0;
296 setLength(len);
297}
298
299String String::token(const char *delim, size_t offset)
300{
301 char *ptr = getText();
302 size_t len = getLength();
303 size_t chars = 0;
304 String result;
305 bool found = false;
306
307 if(offset >= len)
308 return result;
309
310 len -= offset;
311 ptr += offset;
312
313 while(chars < len) {
314 if(strchr(delim, ptr[chars])) {
315 found = true;
316 break;
317 }
318 ++chars;
319 }
320
321 if(!chars && found)
322 erase(offset, 1);
323
324 if(!chars)
325 return result;
326
327 result.set(ptr, chars);
328 if(found)
329 ++chars;
330 erase(offset, chars);
331 return result;
332}
333
334void String::strip(const char *chars)
335{
336 size_t len = strtrim(chars, getText(), getLength());
337 if(!len) {
338 setLength(len);
339 return;
340 }
341 setLength(strchop(chars, getText(), len));
342}
343
344#ifdef HAVE_SNPRINTF
345const char *String::set(size_t chars, const char *format, ...)
346{
347 va_list args;
348 va_start(args, format);
349
350 if(chars <= minsize)
351 clear();
352
353 if(chars > getSize())
354 resize(chars);
355
356 char *ptr = getText();
357 vsnprintf(ptr, chars, format, args);
358 setLength(strlen(ptr));
359 va_end(args);
360 return ptr;
361}
362
363void String::append(size_t chars, const char *format, ...)
364{
365 va_list args;
366 va_start(args, format);
367 size_t len = getLength();
368
369 if(len + chars <= minsize)
370 clear();
371
372 if(len + chars > getSize())
373 resize(len + chars);
374
375 char *ptr = getText() + len;
376 vsnprintf(ptr, chars, format, args);
377 setLength(strlen(getText()));
378 va_end(args);
379}
380
381#endif
382const char *String::set(const char *str, size_t len)
383{
384 if(!str) {
385 clear();
386 return str;
387 }
388
389 if(!len)
390 len = strlen(str);
391
392 // if we are making a short string, lets clear prior alloc
393
394 if(len < minsize)
395 clear();
396
397 if(len >= getSize())
398 resize(len + 1);
399 memmove(getText(), str, len);
400 getText()[len] = 0;
401 setLength(len);
402 return str;
403}
404
405void String::set(const String &str)
406{
407 set(str.getText(), str.getLength());
408}
409
410void String::append(const String &str)
411{
412 append(str.getText(), str.getLength());
413}
414
415
416void String::copy(const String &original)
417{
418 clear();
419
420 if(original.getLength() < minsize) {
421 content.ministring.length = (unsigned)original.getLength();
422 memmove(content.ministring.text, original.getText(), original.getLength() + 1);
423 content.ministring.big = false;
424 return;
425 }
426
427// ptr = original.getText();
428 content.bigstring.length = original.getLength();
429 content.bigstring.size = setSize(original.getLength() + 1);
430 content.bigstring.text = getSpace(original.getLength() + 1);
431 content.ministring.big = true;
432 memmove(content.bigstring.text, original.getText(), original.getLength() + 1);
433}
434
435String::~String()
436{
437 clear();
438}
439
440void String::init(void)
441{
442 content.ministring.big = false;
443 content.ministring.length = 0;
444 content.ministring.text[0] = 0;
445}
446
447size_t String::search(const char *cp, size_t clen, size_t ind) const
448{
449 size_t len = getLength();
450
451 if(!cp)
452 cp = "";
453
454 if(!clen)
455 clen = strlen(cp);
456
457 while(clen + ind <= len) {
458 if(compare(cp, clen, ind) == 0)
459 return ind;
460 ++ind;
461 }
462 return npos;
463}
464
465size_t String::find(const char *cp, size_t ind, size_t len, unsigned instance) const
466{
467 size_t pos = npos;
468
469 if(!cp)
470 cp = "";
471
472 if(!len)
473 len = strlen(cp);
474
475 while(instance--) {
476 pos = search(cp, len, ind);
477 if(pos == npos)
478 break;
479 ind = pos + 1;
480 }
481 return pos;
482}
483
484size_t String::rfind(const char *cp, size_t ind, size_t len) const
485{
486 size_t result = npos;
487
488 if(!cp)
489 cp = "";
490
491 if(!len)
492 len = strlen(cp);
493
494 for(;;) {
495 ind = search(cp, len, ind);
496 if(ind == npos)
497 break;
498 result = ind++;
499 }
500 return result;
501}
502
503unsigned String::count(const char *cp, size_t ind, size_t len) const
504{
505 unsigned chars = 0;
506 if(!cp)
507 cp = "";
508
509 if(!len)
510 len = strlen(cp);
511
512 for(;;) {
513 ind = search(cp, len, ind);
514 if(ind == npos)
515 break;
516 ++chars;
517 ++ind;
518 }
519 return chars;
520}
521
522unsigned String::count(const String &str, size_t ind) const
523{
524 return count(str.getText(), ind, str.getLength());
525}
526
527size_t String::find(const String &str, size_t ind, unsigned instance) const
528{
529 return find(str.getText(), ind, str.getLength(), instance);
530}
531
532size_t String::rfind(const String &str, size_t ind) const
533{
534 return rfind(str.getText(), ind, str.getLength());
535}
536
537int String::compare(const char *cp, size_t len, size_t ind) const
538{
539 if(!cp)
540 cp = "";
541
542 if(ind > getLength())
543 return -1;
544
545 if(!len)
546 return strcmp(getText() + ind, cp);
547
548 return strncmp(getText() + ind, cp, len);
549}
550
551bool String::isEmpty(void) const
552{
553 char *ptr = getText();
554
555 if(!ptr || !*ptr)
556 return true;
557
558 return false;
559}
560
561void String::resize(size_t chars)
562{
563 size_t len = getLength();
564 char *ptr;
565
566 if(len >= chars)
567 len = chars - 1;
568
569 ++len;
570
571 if(!isBig() && chars <= minsize)
572 return;
573
574 if(!isBig()) {
575 ptr = getSpace(chars);
576 memmove(ptr, content.ministring.text, len);
577 ptr[--len] = 0;
578 content.ministring.big = true;
579 content.bigstring.text = ptr;
580 content.bigstring.length = len;
581 setSize(chars);
582 return;
583 }
584
585 if(chars <= minsize && getSize() > slotlimit) {
586 ptr = getText();
587 memmove(content.ministring.text, ptr, len);
588 content.ministring.text[--len] = 0;
589 content.ministring.big = false;
590 content.ministring.length = (unsigned)len;
591 delete[] ptr;
592 return;
593 }
594
595 ptr = getSpace(chars);
596 memmove(ptr, getText(), len);
597 ptr[--len] = 0;
598 clear();
599 setSize(chars);
600 content.bigstring.length = len;
601 content.bigstring.text = ptr;
602 content.ministring.big = true;
603}
604
605void String::clear(void)
606{
607 char **next;
608 unsigned slot;
609
610 if(!isBig())
611 goto end;
612
613 if(!content.bigstring.text)
614 goto end;
615
616 if(getSize() > slotlimit) {
617 delete[] content.bigstring.text;
618 goto end;
619 }
620
621 slot = ((unsigned)getSize() - 1) / slotsize;
622 next = (char **)content.bigstring.text;
623 mutex.enterMutex();
624 *next = idx[slot];
625 idx[slot] = content.bigstring.text;
626 setLength(0);
627 content.bigstring.text = NULL;
628 mutex.leaveMutex();
629
630end:
631 init();
632 return;
633}
634
635char *String::getSpace(size_t chars)
636{
637 unsigned slot;
638 char *cp, **next;
639
640 if(chars > slotlimit)
641 return new char[chars];
642
643 slot = (unsigned)chars / slotsize;
644 mutex.enterMutex();
645 if(!pager) {
646 pager = new MemPager(pagesize);
647 idx = (char **)pager->alloc(sizeof(char *) * slotcount);
648 memset(idx, 0, sizeof(char *) * slotcount);
649 }
650 cp = idx[slot];
651 if(cp) {
652 next = (char **)cp;
653 idx[slot] = *next;
654 }
655 else
656 cp = (char *)pager->alloc(++slot * slotsize);
657 mutex.leaveMutex();
658 return cp;
659}
660
661const char *String::getIndex(size_t ind) const
662{
663 const char *dp = getText();
664
665 if(ind > getLength())
666 return NULL;
667
668 return (const char *)dp + ind;
669}
670
671char *String::getText(void) const
672{
673 if(isBig())
674 return (char *)content.bigstring.text;
675
676 return (char *)content.ministring.text;
677}
678
679long String::getValue(long def) const
680{
681 unsigned base = 10;
682 char *cp = getText();
683 char *ep = 0;
684 long val;
685
686 if(!cp)
687 return def;
688
689 if(!strnicmp(cp, "0x", 2)) {
690 cp += 2;
691 base = 16;
692 }
693
694 val = ::strtol(cp, &ep, base);
695 if(!ep || *ep)
696 return def;
697 return val;
698}
699
700bool String::getBool(bool def) const
701{
702 char *cp = getText();
703
704 if(!cp)
705 return def;
706
707 if(isdigit(*cp)) {
708 if(!getValue(0))
709 return false;
710 return true;
711 }
712
713 if(!stricmp(cp, "true") || !stricmp(cp, "yes"))
714 return true;
715
716 if(!stricmp(cp, "false") || !stricmp(cp, "no"))
717 return false;
718
719 return def;
720}
721
722const size_t String::getSize(void) const
723{
724 if(isBig())
725 return content.bigstring.size;
726
727 return minsize;
728}
729
730void String::setLength(size_t len)
731{
732 if(isBig())
733 content.bigstring.length = len;
734 else
735 content.ministring.length = (unsigned)len;
736}
737
738size_t String::setSize(size_t chars)
739{
740 if(chars <= minsize && !isBig())
741 return minsize;
742
743 if(chars <= slotlimit) {
744 size_t slotcount = chars / slotsize;
745 if((chars % slotsize)!=0) ++slotcount;
746 chars = slotcount*slotsize;
747 }
748 content.bigstring.size = chars;
749 return chars;
750}
751
752const size_t String::getLength(void) const
753{
754 if(isBig())
755 return content.bigstring.length;
756
757 return content.ministring.length;
758}
759
760String operator+(const String &s1, const char c2)
761{
762 String result(s1);
763 result.add(c2);
764 return result;
765}
766
767String operator+(const String &s1, const String &s2)
768{
769 String result(s1);
770 result.append(s2);
771 return result;
772}
773
774String operator+(const String &s1, const char *s2)
775{
776 String result(s1);
777 result += s2;
778 return result;
779}
780
781String operator+(const char *s1, const String &s2)
782{
783 String result(s1);
784 result += s2;
785 return result;
786}
787
788String operator+(const char c1, const String &s2)
789{
790 String result(1, c1);
791 result += s2;
792 return result;
793}
794
795bool String::operator<(const String &s1) const
796{
797 if(compare(s1.getText()) < 0)
798 return true;
799
800 return false;
801}
802
803bool String::operator<(const char *s1) const
804{
805 if(compare(s1) < 0)
806 return true;
807
808 return false;
809}
810
811bool String::operator>(const String &s1) const
812{
813 if(compare(s1.getText()) > 0)
814 return true;
815
816 return false;
817}
818
819bool String::operator>(const char *s1) const
820{
821 if(compare(s1) > 0)
822 return true;
823
824 return false;
825}
826
827bool String::operator<=(const String &s1) const
828{
829 if(compare(s1.getText()) <= 0)
830 return true;
831
832 return false;
833}
834
835bool String::operator<=(const char *s1) const
836{
837 if(compare(s1) <= 0)
838 return true;
839
840 return false;
841}
842
843bool String::operator>=(const String &s1) const
844{
845 if(compare(s1.getText()) >= 0)
846 return true;
847
848 return false;
849}
850
851bool String::operator>=(const char *s1) const
852{
853 if(compare(s1) >= 0)
854 return true;
855
856 return false;
857}
858
859bool String::operator==(const String &s1) const
860{
861 if(compare(s1.getText()) == 0)
862 return true;
863
864 return false;
865}
866
867bool String::operator==(const char *s1) const
868{
869 if(compare(s1) == 0)
870 return true;
871
872 return false;
873}
874
875bool String::operator!=(const String &s1) const
876{
877 if(compare(s1.getText()) != 0)
878 return true;
879
880 return false;
881}
882
883bool String::operator!=(const char *s1) const
884{
885 if(compare(s1) != 0)
886 return true;
887
888 return false;
889}
890
891bool String::operator*=(const String &s1) const
892{
893 return search(s1.getText(), s1.getLength()) != npos;
894}
895
896bool String::operator*=(const char *s) const
897{
898 return search(s) != npos;
899}
900
901std::ostream &operator<<(std::ostream &os, const String &str)
902{
903 os << str.getText();
904 return os;
905}
906
907void *StringObject::operator new(size_t size) NEW_THROWS
908{
909 char *base;
910 size_t *sp;
911 size += sizeof(size_t);
912
913 if(size > String::slotlimit)
914 return NULL;
915
916 base = String::getSpace(size);
917
918 if(!base)
919 return NULL;
920
921 sp = (size_t *)base;
922 *sp = size;
923 base += sizeof(size_t);
924 return (void *)base;
925}
926
927void StringObject::operator delete(void *ptr)
928{
929 char **next;
930 unsigned slot;
931 size_t *size = (size_t *)ptr;
932
933 --size;
934 ptr = size;
935
936 slot = (unsigned)(((*size) - 1) / String::slotsize);
937 next = ((char **)(ptr));
938 mutex.enter();
939 *next = String::idx[slot];
940 String::idx[slot] = (char *)ptr;
941 mutex.leave();
942}
943
944std::istream &getline(std::istream &is, String &str, char delim, size_t len)
945{
946 if(!len)
947 len = str.getSize() - 1;
948
949 if(len >= str.getSize())
950 str.resize(len + 1);
951
952 char *ptr = str.getText();
953 is.getline(ptr, (std::streamsize)len, delim);
954 str.setLength(strlen(ptr));
955 return is;
956}
957
958SString::SString() :
959String(), streambuf()
960#ifdef HAVE_OLD_IOSTREAM
961,ostream()
962#else
963,ostream((streambuf *)this)
964#endif
965{
966#ifdef HAVE_OLD_IOSTREAM
967 ostream::init((streambuf *)this);
968#endif
969}
970
971SString::SString(const SString &from) :
972String(from), streambuf()
973#ifdef HAVE_OLD_IOSTREAM
974,ostream()
975#else
976,ostream((streambuf *)this)
977#endif
978{
979#ifdef HAVE_OLD_IOSTREAM
980 ostream::init((streambuf *)this);
981#endif
982}
983
984SString::~SString()
985{
986 if(isBig())
987 String::clear();
988}
989
990int SString::overflow(int c)
991{
992 String::add((char)(c));
993 return c;
994}
995
996#ifdef HAVE_SNPRINTF
997int strprintf(String &str, size_t size, const char *format, ...)
998{
999 va_list args;
1000 va_start(args, format);
1001 int rtn;
1002
1003 if(!size)
1004 size = str.getSize();
1005
1006 if(size > str.getSize())
1007 str.resize(size);
1008
1009 char *ptr = str.getText();
1010 str.setLength(0);
1011 ptr[0] = 0;
1012 rtn = vsnprintf(ptr, size, format, args);
1013 str.setLength(strlen(ptr));
1014 va_end(args);
1015 return rtn;
1016}
1017#endif
1018
1019#ifdef CCXX_NAMESPACES
1020}
1021#endif
1022
1023/** EMACS **
1024 * Local variables:
1025 * mode: c++
1026 * c-basic-offset: 4
1027 * End:
1028 */