ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GStr.cpp
Revision: 2
Committed: Mon Mar 22 22:03:27 2010 UTC (9 years, 10 months ago) by gpertea
File size: 33515 byte(s)
Log Message:
added my gclib source files

Line File contents
1 //---------------------------------------------------------------------------
2 #include "GStr.h"
3 #include <stdio.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include "GBase.h"
7 #include <stdarg.h>
8 #include <errno.h>
9
10 //---------------------------------------------------------------------------
11
12 GStr::Data GStr::null_data;
13
14 //=========================================
15
16 GStr::Data * GStr::new_data(int length) {
17 //static method to return a new Data object (allocate length)
18 //content is undefined, but it's null terminated
19 if (length > 0) {
20 Data* data;
21 GMALLOC(data, sizeof(Data)+length);
22 data->ref_count = 0;
23 data->length = length;
24 data->chars[length] = '\0';
25 return data;
26 }
27 else
28 return &null_data;
29 }
30
31 GStr::Data* GStr::new_data(const char* str) {
32 //static method to return a new Data object (allocate length)
33 //as a copy of a given string
34 if (str==NULL) return &null_data;
35 int length=strlen(str);
36 if (length > 0) {
37 Data* data;
38 GMALLOC(data, sizeof(Data)+length);
39 strcpy(data->chars, str);
40 data->ref_count = 0;
41 data->length = length;
42 data->chars[length] = '\0';
43 return data;
44 }
45 else
46 return &null_data;
47 }
48
49 void GStr::replace_data(int len) {
50
51 if (len == my_data->length && my_data->ref_count <= 1)
52 return;
53
54 if (my_data != &null_data && --my_data->ref_count == 0)
55 GFREE(my_data);
56
57 if (len > 0) {
58 //my_data = (Data *) malloc(sizeof(Data) + len);
59 GMALLOC(my_data, sizeof(Data) + len);
60 my_data->ref_count = 1;
61 my_data->length = len;
62 my_data->chars[len] = '\0';
63 }
64 else
65 my_data = &null_data;
66 }
67
68 void GStr::replace_data(Data *data) {
69 if (my_data != &null_data && --my_data->ref_count == 0)
70 GFREE(my_data);
71 if (data != &null_data)
72 data->ref_count++;
73 my_data = data;
74 }
75
76 void GStr::make_unique() {//make sure is not a reference to other string
77 if (my_data->ref_count > 1) {
78 Data *data = new_data(length());
79 ::memcpy(data->chars, chars(), length());
80 my_data->ref_count--;
81 my_data = data;
82 my_data->ref_count++;
83 }
84 }
85
86 bool operator==(const char *s1, const GStr& s2){
87 if (s1==NULL) return s2.is_empty();
88 return (strcmp(s1, s2.chars()) == 0);
89 }
90
91 bool operator<(const char *s1, const GStr& s2) {
92 if (s1==NULL) return !s2.is_empty();
93 return (strcmp(s1, s2.chars()) < 0);
94 }
95
96 bool operator<=(const char *s1, const GStr& s2){
97 if (s1==NULL) return true;
98 return (strcmp(s1, s2.chars()) <= 0);
99 }
100
101 bool operator>(const char *s1, const GStr& s2) {
102 if (s1==NULL) return false;
103 return (strcmp(s1, s2.chars()) > 0);
104 }
105
106
107 GStr::GStr():my_data(&null_data) {
108 fTokenDelimiter=NULL;
109 fLastTokenStart=0;
110 readbuf=NULL;
111 }
112
113 GStr::GStr(const GStr& s): my_data(&null_data){
114 fTokenDelimiter=NULL;
115 fLastTokenStart=0;
116 readbuf=NULL;
117 replace_data(s.my_data);
118 }
119
120 GStr::GStr(const char *s): my_data(&null_data) {
121 fTokenDelimiter=NULL;
122 fLastTokenStart=0;
123 readbuf=NULL;
124 my_data=new_data(s);
125 my_data->ref_count = 1;
126 }
127
128 GStr::GStr(const int i): my_data(&null_data) {
129 fTokenDelimiter=NULL;
130 fLastTokenStart=0;
131 readbuf=NULL;
132 char buf[20];
133 sprintf(buf,"%d",i);
134 const int len = ::strlen(buf);
135 replace_data(len);
136 ::memcpy(chrs(), buf, len);
137 }
138
139 GStr::GStr(const double f): my_data(&null_data) {
140 fTokenDelimiter=NULL;
141 fLastTokenStart=0;
142 readbuf=NULL;
143 char buf[20];
144 sprintf(buf,"%f",f);
145 const int len = ::strlen(buf);
146 replace_data(len);
147 ::memcpy(chrs(), buf, len);
148 }
149
150 GStr::GStr(char c, int n): my_data(&null_data) {
151 fTokenDelimiter=NULL;
152 fLastTokenStart=0;
153 readbuf=NULL;
154 replace_data(n); ::memset(chrs(), c, n);
155 }
156
157 GStr::~GStr() {
158 if (my_data != &null_data && --my_data->ref_count == 0)
159 GFREE(my_data);
160 GFREE(fTokenDelimiter);
161 GFREE(readbuf);
162 }
163
164 char& GStr::operator[](int idx){
165 //returns reference to char (can be l-value)
166 if (idx < 0) idx += length();
167 if (idx < 0 || idx >= length()) invalid_index_error("operator[]");
168 make_unique(); //because the user will probably modify this char!
169 return chrs()[idx];
170 }
171
172 char GStr::operator[](int idx) const {
173 //returns char copy (cannot be l-value!)
174 if (idx < 0) idx += length();
175 if (idx < 0 || idx >= length()) invalid_index_error("operator[]");
176 return chars()[idx];
177 }
178
179 GStr& GStr::operator=(const GStr& s) {
180 make_unique(); //edit operation ahead
181 replace_data(s.my_data);
182 return *this;
183 }
184
185 GStr& GStr::operator=(const char *s) {
186 make_unique(); //edit operation ahead
187 if (s==NULL) {
188 replace_data(0);
189 return *this;
190 }
191 const int len = ::strlen(s); replace_data(len);
192 ::memcpy(chrs(), s, len);
193 return *this;
194 }
195
196 GStr& GStr::operator=(const double f) {
197 make_unique(); //edit operation ahead
198 char buf[20];
199 sprintf(buf,"%f",f);
200 const int len = ::strlen(buf);
201 replace_data(len);
202 ::memcpy(chrs(), buf, len);
203 return *this;
204 }
205
206 GStr& GStr::operator=(const int i) {
207 make_unique(); //edit operation ahead
208 char buf[20];
209 sprintf(buf,"%d",i);
210 const int len = ::strlen(buf);
211 replace_data(len);
212 ::memcpy(chrs(), buf, len);
213 return *this;
214 }
215
216 bool GStr::operator==(const GStr& s) const {
217 if (s.is_empty()) return is_empty();
218 return (length() == s.length()) &&
219 (memcmp(chars(), s.chars(), length()) == 0);
220 }
221
222 bool GStr::operator==(const char *s) const {
223 if (s==NULL) return is_empty();
224 return (strcmp(chars(), s) == 0);
225 }
226
227 bool GStr::operator<(const GStr& s) const {
228 if (s.is_empty()) return false;
229 return (strcmp(chars(), s.chars()) < 0);
230 }
231
232 bool GStr::operator<(const char *s) const {
233 if (s==NULL) return false;
234 return (strcmp(chars(), s) < 0);
235 }
236
237 bool GStr::operator<=(const GStr& s) const {
238 if (s.is_empty()) return is_empty();
239 return (strcmp(chars(), s.chars()) <= 0);
240 }
241
242 bool GStr::operator<=(const char *s) const {
243 if (s==NULL) return is_empty();
244 return (strcmp(chars(), s) <= 0);
245 }
246
247 bool GStr::operator>(const GStr& s) const {
248 if (s.is_empty()) return !is_empty();
249 return (strcmp(chars(), s.chars()) > 0);
250 }
251
252 bool GStr::operator>(const char *s) const {
253 if (s==NULL) return !is_empty();
254 return (strcmp(chars(), s) > 0);
255 }
256
257 bool GStr::operator>=(const GStr& s) const {
258 if (s.is_empty()) return true;
259 return (strcmp(chars(), s.chars()) >= 0);
260 }
261
262 bool GStr::operator>=(const char *s) const {
263 if (s==NULL) return true;
264 return (strcmp(chars(), s) >= 0);
265 }
266
267 bool GStr::operator!=(const GStr& s) const {
268 if (s.is_empty()) return !is_empty();
269 return (length() != s.length()) ||
270 (memcmp(chars(), s.chars(), length()) != 0);
271 }
272
273 bool GStr::operator!=(const char *s) const {
274 if (s==NULL) return !is_empty();
275 return (strcmp(chars(), s) != 0);
276 }
277
278 GStr& GStr::operator+=(const GStr& s) {
279 return append((const char *)s);
280 }
281
282 GStr& GStr::operator+=(const char* s) {
283 return append(s);
284 }
285
286 GStr& GStr::operator+=(const char c) {
287 char buf[4];
288 sprintf(buf,"%c",c);
289 return append(buf);
290 }
291
292 GStr& GStr::operator+=(const int i) {
293 char buf[20];
294 sprintf(buf,"%d",i);
295 return append(buf);
296 }
297
298
299 GStr& GStr::operator+=(const double f) {
300 char buf[30];
301 sprintf(buf,"%f",f);
302 return append(buf);
303 }
304
305 bool GStr::is_empty() const {
306 //return my_data == &null_data;
307 return (length()==0);
308 }
309
310 GStr GStr::copy() const {
311 GStr newstring(*this);
312 return newstring;
313 }
314
315 GStr& GStr::clear() {
316 make_unique(); //edit operation ahead
317 replace_data(0);
318 return *this;
319 }
320
321 int GStr::index(const GStr& s, int start_index) const {
322 return index(s.chars(), start_index);
323 }
324
325 bool GStr::contains(const GStr& s) const {
326 return (index(s, 0) >= 0);
327 }
328
329 bool GStr::contains(const char *s) const {
330 return (index(s, 0) >= 0);
331 }
332
333 bool GStr::startsWith(const char *s) const {
334 return (index(s, 0) == 0);
335 }
336
337 bool GStr::contains(char c) const {
338 return (index(c, 0) >= 0);
339 }
340 GStr& GStr::format(const char *fmt,...) {
341 // Format as in sprintf
342 make_unique(); //edit operation ahead
343 char* buf;
344 GMALLOC(buf, strlen(fmt)+1024);
345 va_list arguments;
346 va_start(arguments,fmt);
347 //+1K buffer, should be enough for common expressions
348 int len=vsprintf(buf,fmt,arguments);
349 va_end(arguments);
350 replace_data(len); //this also adds the '\0' at the end!
351 //and sets the right len
352 ::memcpy(chrs(), buf, len);
353 GFREE(buf);
354 return *this;
355 }
356
357 GStr& GStr::appendfmt(const char *fmt,...) {
358 // Format as in sprintf
359 make_unique(); //edit operation ahead
360 char* buf;
361 GMALLOC(buf, strlen(fmt)+1024);
362 va_list arguments;
363 va_start(arguments,fmt);
364 //+1K buffer, should be enough for common expressions
365 vsprintf(buf,fmt,arguments);
366 va_end(arguments);
367 append(buf);
368 GFREE(buf);
369 return *this;
370 }
371
372 GStr& GStr::trim(char c) {
373 register int istart;
374 register int iend;
375 for (istart=0; istart<length() && chars()[istart]==c;istart++);
376 if (istart==length()) {
377 make_unique(); //edit operation ahead
378 replace_data(0); //string was entirely trimmed
379 return *this;
380 }
381 for (iend=length()-1; iend>istart && chars()[iend]==c;iend--);
382 int newlen=iend-istart+1;
383 if (newlen==length()) //nothing to trim
384 return *this;
385 make_unique(); //edit operation ahead
386 Data *data = new_data(newlen);
387 ::memcpy(data->chars, &chars()[istart], newlen);
388 replace_data(data);
389 return *this;
390 }
391
392 GStr& GStr::trim(const char* c) {
393 register int istart;
394 register int iend;
395 for (istart=0; istart<length() && strchr(c, chars()[istart])!=NULL ;istart++);
396 if (istart==length()) {
397 replace_data(0); //string was entirely trimmed
398 return *this;
399 }
400 for (iend=length()-1; iend>istart && strchr(c, chars()[iend])!=NULL;iend--);
401 int newlen=iend-istart+1;
402 if (newlen==length()) //nothing to trim
403 return *this;
404 make_unique(); //edit operation ahead
405 Data *data = new_data(newlen);
406 ::memcpy(data->chars, &chars()[istart], newlen);
407 replace_data(data);
408 return *this;
409 }
410
411 GStr& GStr::trimR(char c) {
412 //only trim the right end
413 //register int istart;
414 register int iend;
415 for (iend=length()-1; iend>=0 && chars()[iend]==c;iend--);
416 if (iend==-1) {
417 replace_data(0); //string was entirely trimmed
418 return *this;
419 }
420 int newlen=iend+1;
421 if (newlen==length()) //nothing to trim
422 return *this;
423 make_unique(); //edit operation ahead
424
425 Data *data = new_data(newlen);
426 ::memcpy(data->chars, chars(), newlen);
427 replace_data(data);
428 return *this;
429 }
430
431 GStr& GStr::trimR(const char* c) {
432 register int iend;
433 for (iend=length()-1; iend>=0 && strchr(c,chars()[iend])!=NULL;iend--);
434 if (iend==-1) {
435 replace_data(0); //string was entirely trimmed
436 return *this;
437 }
438 int newlen=iend+1;
439 if (newlen==length()) //nothing to trim
440 return *this;
441 make_unique(); //edit operation ahead
442 Data *data = new_data(newlen);
443 ::memcpy(data->chars, chars(), newlen);
444 replace_data(data);
445 return *this;
446 }
447
448
449 GStr& GStr::chomp(const char* cstr) {
450 register int iend;
451 if (cstr==NULL || *cstr==0) return *this;
452 //check if this ends with cstr
453 int cend=strlen(cstr)-1;
454 iend=my_data->length-1;
455 while (iend>=0 && cend>=0) {
456 if (my_data->chars[iend]!=cstr[cend]) return *this;
457 iend--;
458 cend--;
459 }
460 if (iend==-1) {
461 replace_data(0); //string will be entirely trimmed
462 return *this;
463 }
464 int newlen=iend+1;
465 make_unique(); //edit operation ahead
466 Data *data = new_data(newlen);
467 ::memcpy(data->chars, chars(), newlen);
468 replace_data(data);
469 return *this;
470 }
471
472 GStr& GStr::trimL(char c) {
473 register int istart;
474 for (istart=0; istart<length() && chars()[istart]==c;istart++);
475 if (istart==length()) {
476 replace_data(0); //string was entirely trimmed
477 return *this;
478 }
479 int newlen=length()-istart;
480 if (newlen==length()) //nothing to trim
481 return *this;
482 make_unique(); //edit operation ahead
483 Data *data = new_data(newlen);
484 ::memcpy(data->chars, &chars()[istart], newlen);
485 replace_data(data);
486 return *this;
487 }
488
489 GStr& GStr::trimL(const char* c) {
490 register int istart;
491 for (istart=0; istart<length() && strchr(c,chars()[istart])!=NULL;istart++);
492 if (istart==length()) {
493 replace_data(0); //string was entirely trimmed
494 return *this;
495 }
496 int newlen=length()-istart;
497 if (newlen==length()) //nothing to trim
498 return *this;
499 make_unique(); //edit operation ahead
500
501 Data *data = new_data(newlen);
502 ::memcpy(data->chars, &chars()[istart], newlen);
503 replace_data(data);
504 return *this;
505 }
506
507 GStr& GStr::padR(int len, char c) {
508 //actually means align right in len
509 if (length()>=len) return *this; //no room for padding
510 make_unique(); //edit operation ahead
511 Data *data = new_data(len);
512 ::memset(data->chars,c,len-length());
513 ::memcpy(&data->chars[len-length()], chars(), length());
514 replace_data(data);
515 return *this;
516 }
517
518 GStr& GStr::padL(int len, char c) { //align left the string
519 if (length()>=len) return *this; //no room for padding
520 make_unique(); //edit operation ahead
521 Data *data = new_data(len);
522 ::memcpy(data->chars, chars(), length());
523 ::memset(&data->chars[length()],c,len-length());
524 replace_data(data);
525 return *this;
526 }
527
528 GStr& GStr::padC(int len, char c) {
529 if (length()>=len) return *this; //no room for padding
530 make_unique(); //edit operation ahead
531 int istart=(len-length())/2;
532 Data *data = new_data(len);
533 if (istart>0)
534 ::memset(data->chars, c, istart);
535 ::memcpy(&data->chars[istart], chars(), length());
536 int iend=istart+length();
537 if (iend<len)
538 ::memset(&data->chars[iend],c,len-iend);
539 replace_data(data);
540 return *this;
541 }
542
543 GStr operator+(const char *s1, const GStr& s2) {
544 const int s1_length = ::strlen(s1);
545
546 if (s1_length == 0)
547 return s2;
548 else {
549 GStr newstring;
550 newstring.replace_data(s1_length + s2.length());
551 ::memcpy(newstring.chrs(), s1, s1_length);
552 ::memcpy(&(newstring.chrs())[s1_length], s2.chars(), s2.length());
553 return newstring;
554 }
555 }
556
557 //=========================================
558
559 GStr GStr::operator+(const GStr& s) const {
560 if (length() == 0)
561 return s;
562 else if (s.length() == 0)
563 return *this;
564 else {
565 GStr newstring;
566 newstring.replace_data(length() + s.length());
567 ::memcpy(newstring.chrs(), chars(), length());
568 ::memcpy(&(newstring.chrs())[length()], s.chars(), s.length());
569 return newstring;
570 }
571 }
572
573 //=========================================
574
575 GStr GStr::operator+(const char *s) const {
576
577 const int s_length = ::strlen(s);
578
579 if (s_length == 0)
580 return *this;
581 else {
582 GStr newstring;
583 newstring.replace_data(length() + s_length);
584 ::memcpy(newstring.chrs(), chars(), length());
585 ::memcpy(&(newstring.chrs())[length()], s, s_length);
586 return newstring;
587 }
588 }
589
590 GStr GStr::operator+(const int i) const {
591 char buf[20];
592 sprintf(buf, "%d", i);
593 const int s_length = ::strlen(buf);
594 GStr newstring;
595 newstring.replace_data(length() + s_length);
596 ::memcpy(newstring.chrs(), chars(), length());
597 ::memcpy(&(newstring.chrs())[length()], buf, s_length);
598 return newstring;
599 }
600
601 GStr GStr::operator+(const char c) const {
602 char buf[4];
603 sprintf(buf, "%c", c);
604 const int s_length = ::strlen(buf);
605 GStr newstring;
606 newstring.replace_data(length() + s_length);
607 ::memcpy(newstring.chrs(), chars(), length());
608 ::memcpy(&(newstring.chrs())[length()], buf, s_length);
609 return newstring;
610 }
611
612 GStr GStr::operator+(const double f) const {
613 char buf[30];
614 sprintf(buf, "%f", f);
615 const int s_length = ::strlen(buf);
616 GStr newstring;
617 newstring.replace_data(length() + s_length);
618 ::memcpy(newstring.chrs(), chars(), length());
619 ::memcpy(&(newstring.chrs())[length()], buf, s_length);
620 return newstring;
621 }
622
623
624 //=========================================
625
626 bool GStr::is_space() const {
627
628 if (my_data == &null_data)
629 return false;
630
631 for (register const char *p = chars(); *p; p++)
632 if (!isspace(*p))
633 return false;
634
635 return true;
636 }
637
638 //=========================================
639
640 GStr GStr::substr(int idx, int len) const {
641 // A negative idx specifies an idx from the right of the string.
642 if (idx < 0)
643 idx += length();
644
645 // A length of -1 specifies the rest of the string.
646 if (len == -1 || len>length()-idx)
647 len = length() - idx;
648
649 if (idx<0 || idx>=length() || len<0 )
650 invalid_args_error("substr()");
651
652 GStr newstring;
653 newstring.replace_data(len);
654 ::memcpy(newstring.chrs(), &chars()[idx], len);
655 return newstring;
656 }
657
658
659 //transform: any character from 'from' is replaced with a coresponding
660 //char from 'to'
661
662 GStr& GStr::tr(const char *rfrom, const char* rto) {
663 if (length() == 0 || rfrom==NULL || strlen(rfrom)==0)
664 return *this;
665 unsigned int l=strlen(rfrom);
666 if (rto!=NULL && strlen(rto)!=l)
667 invalid_args_error("tr()");
668 make_unique(); //edit operation ahead
669 Data *data = new_data(length());
670
671 if (rto==NULL) { //deletion case
672 char* s = my_data->chars;
673 char* p;
674 char* dest = data->chars;
675 do {
676 if ((p=strpbrk(s,rfrom))!=NULL) {
677 memcpy(dest,s,p-s);
678 dest+=p-s;
679 s=p+1;
680 }
681 else {
682 strcpy(dest, s);
683 dest+=strlen(s);
684 }
685 } while (p!=NULL);
686 (*dest)='\0';
687 }
688 else { //char substitution case - easier!
689 const char* p;
690 for (int i=0; i<length(); i++) {
691 if ((p=strchr(rfrom, my_data->chars[i]))!=NULL)
692 my_data->chars[i]=rto[p-rfrom];
693 }
694 }
695 data->length=strlen(data->chars);
696 replace_data(data);
697 return *this;
698 }
699
700
701 // search and replace all the occurences of a string with another string
702 // or just remove the given string (if replacement is NULL)
703 GStr& GStr::replace(const char *rfrom, const char* rto) {
704 if (length() == 0 || rfrom==NULL || strlen(rfrom)==0)
705 return *this;
706 unsigned int l=strlen(rfrom);
707 unsigned int tl= (rto==NULL)?0:strlen(rto);
708 make_unique(); //edit operation ahead
709 char* p;
710 char* dest;
711 char* newdest=NULL;
712 char* s = my_data->chars;
713 if (tl!=l) { //reallocation
714 if (tl>l) { //possible enlargement
715 GMALLOC(newdest, length()*(tl-l+1)+1);
716 }
717 else {//delete or replace with a shorter string
718 GMALLOC(newdest, length() + 1);
719 }
720 dest=newdest;
721 if (tl==0) {//deletion
722 while ((p=strstr(s,rfrom))!=NULL) {
723 //rfrom found at position p
724 memcpy(dest,s,p-s);
725 dest+=p-s;
726 s+=p-s+l; //s positioned in string after rfrom
727 }
728 //no more occurences, copy the remaining string
729 strcpy(dest, s);
730 }
731 else { //replace with another string
732 while ((p=strstr(s,rfrom))!=NULL) {
733 memcpy(dest,s,p-s); //copy up rto the match
734 dest+=p-s;
735 memcpy(dest,rto,tl); //put the replacement string
736 dest+=tl;
737 s+=p-s+l;
738 }
739 //not found any more, copy rto end of string
740 strcpy(dest, s);
741 }
742 Data* data=new_data(newdest);
743 replace_data(data);
744 GFREE(newdest);
745 }
746 else { //inplace editing: no need rto reallocate
747 while ((p=strstr(s,rfrom))!=NULL) {
748 memcpy(p,rto,l);
749 s+=p-s+l;
750 }
751 }
752 return *this;
753 }
754
755
756
757 GStr& GStr::cut(int idx, int len) {
758
759 if (len == 0)
760 return *this;
761 make_unique(); //edit operation ahead
762
763 // A negative idx specifies an idx from the right of the string,
764 // so the left part will be cut out
765 if (idx < 0)
766 idx += length();
767
768 // A length of -1 specifies the rest of the string.
769 if (len == -1)
770 len = length() - idx;
771
772 if (idx<0 || idx>=length() || len<0 || len>length()-idx)
773 invalid_args_error("cut()");
774
775 Data *data = new_data(length() - len);
776 if (idx > 0)
777 ::memcpy(data->chars, chars(), idx);
778 ::strcpy(&data->chars[idx], &chars()[idx+len]);
779 replace_data(data);
780
781 return *this;
782 }
783
784 //=========================================
785
786 GStr& GStr::paste(const GStr& s, int idx, int len) {
787 // A negative idx specifies an idx from the right of the string.
788 if (idx < 0)
789 idx += length();
790 make_unique(); //edit operation ahead
791
792 // A length of -1 specifies the rest of the string.
793 if (len == -1)
794 len = length() - idx;
795
796 if (idx<0 || idx>=length() || len<0 || len>length()-idx)
797 invalid_args_error("replace()");
798
799 if (len == s.length() && my_data->ref_count == 1)
800 ::memcpy(&chrs()[idx], s.chars(), len);
801 else {
802 Data *data = new_data(length() - len + s.length());
803 if (idx > 0)
804 ::memcpy(data->chars, chars(), idx);
805 if (s.length() > 0)
806 ::memcpy(&data->chars[idx], s.chars(), s.length());
807 ::strcpy(&data->chars[idx+s.length()], &chars()[idx+len]);
808 replace_data(data);
809 }
810
811 return *this;
812 }
813
814 //=========================================
815
816 GStr& GStr::paste(const char *s, int idx, int len) {
817
818 // A negative idx specifies an idx from the right of the string.
819 make_unique(); //edit operation ahead
820 if (idx < 0)
821 idx += length();
822
823 // A length of -1 specifies the rest of the string.
824 if (len == -1)
825 len = length() - idx;
826
827 if (idx<0 || idx>=length() || len<0 || len>length()-idx)
828 invalid_args_error("replace()");
829
830 const int s_length = ::strlen(s);
831
832 if (len == s_length && my_data->ref_count == 1)
833 ::memcpy(&chrs()[idx], s, len);
834 else {
835 Data *data = new_data(length() - len + s_length);
836 if (idx > 0)
837 ::memcpy(data->chars, chars(), idx);
838 if (s_length > 0)
839 ::memcpy(&data->chars[idx], s, s_length);
840 ::strcpy(&data->chars[idx+s_length], &chars()[idx+len]);
841 replace_data(data);
842 }
843
844 return *this;
845 }
846
847 //=========================================
848
849 GStr& GStr::insert(const GStr& s, int idx) {
850 make_unique(); //edit operation ahead
851
852 // A negative idx specifies an idx from the right of the string.
853 if (idx < 0)
854 idx += length();
855
856 if (idx < 0 || idx >= length())
857 invalid_index_error("insert()");
858
859 if (s.length() > 0) {
860 Data *data = new_data(length() + s.length());
861 if (idx > 0)
862 ::memcpy(data->chars, chars(), idx);
863 ::memcpy(&data->chars[idx], s.chars(), s.length());
864 ::strcpy(&data->chars[idx+s.length()], &chars()[idx]);
865 replace_data(data);
866 }
867
868 return *this;
869 }
870
871 //=========================================
872
873 GStr& GStr::insert(const char *s, int idx) {
874 // A negative idx specifies an idx from the right of the string.
875 make_unique(); //edit operation ahead
876 if (idx < 0)
877 idx += length();
878
879 if (idx < 0 || idx >= length())
880 invalid_index_error("insert()");
881
882 const int s_length = ::strlen(s);
883
884 if (s_length > 0) {
885 Data *data = new_data(length() + s_length);
886 if (idx > 0)
887 ::memcpy(data->chars, chars(), idx);
888 ::memcpy(&data->chars[idx], s, s_length);
889 ::strcpy(&data->chars[idx+s_length], &chars()[idx]);
890 replace_data(data);
891 }
892
893 return *this;
894 }
895 //=========================================
896
897 GStr& GStr::append(const char* s) {
898 make_unique(); //edit operation ahead
899 int len=::strlen(s);
900 int newlength=len+my_data->length;
901 if (newlength<=my_data->length) return *this;
902 if (my_data->length==0) {
903 replace_data(len);
904 ::memcpy(my_data->chars, s, len);
905 return *this;
906 }
907 //faster solution with realloc
908 GREALLOC(my_data, sizeof(Data)+newlength);
909 ::strcpy(&my_data->chars[my_data->length], s);
910 my_data->length=newlength;
911 my_data->chars[newlength]='\0';
912 return *this;
913 }
914
915 GStr& GStr::append(const GStr& s) {
916 return append((const char *)s);
917 }
918
919
920 GStr& GStr::upper() {
921 make_unique(); //edit operation ahead
922 for (register char *p = chrs(); *p; p++)
923 *p = (char) toupper(*p);
924
925 return *this;
926 }
927
928 //=========================================
929
930 GStr& GStr::lower() {
931 make_unique();
932
933 for (register char *p = chrs(); *p; p++)
934 *p = (char) tolower(*p);
935
936 return *this;
937 }
938
939 //=========================================
940
941 int GStr::index(const char *s, int start_index) const {
942 // A negative index specifies an index from the right of the string.
943 if (strlen(s)>(size_t)length()) return -1;
944 if (start_index < 0)
945 start_index += length();
946
947 if (start_index < 0 || start_index >= length())
948 invalid_index_error("index()");
949 const char* idx = strstr(&chars()[start_index], s);
950 if (!idx)
951 return -1;
952 else
953 return idx - chars();
954 }
955
956 //=========================================
957
958 int GStr::index(char c, int start_index) const {
959 // A negative index specifies an index from the right of the string.
960 if (length()==0) return -1;
961 if (start_index < 0)
962 start_index += length();
963
964 if (start_index < 0 || start_index >= length())
965 invalid_index_error("index()");
966
967
968 if (c == '\0')
969 return -1;
970 const char *idx=(char *) ::memchr(&chars()[start_index], c,
971 length()-start_index);
972 if (idx==NULL)
973 return -1;
974 else
975 return idx - chars();
976 }
977
978 int GStr::rindex(char c) const {
979 if (c == '\0' || length()==0)
980 return -1;
981 char* idx= rstrchr((char*)chars(), c);
982 if (idx==NULL) return -1;
983 else return idx-chars();
984 }
985
986 int GStr::rindex(const char* str) const {
987 if (str==NULL || *str == '\0' || length()==0)
988 return -1;
989 char* idx= rstrfind((char*)chars(), str);
990 if (idx==NULL) return -1;
991 else return idx-chars();
992 }
993
994 GStr GStr::split(const char* delim) {
995 /* splits "this" in two parts, at the first (left)
996 encounter of delim:
997 1st would stay in "this",
998 2nd part will be returned
999 as a new string!
1000 */
1001 GStr result;
1002 int i=index(delim);
1003 if (i>=0){
1004 result=substr(i+strlen(delim));
1005 cut(i);
1006 return result;
1007 }
1008 return result;
1009 }
1010
1011 GStr GStr::split(char c) {
1012 /* splits "this" in two parts, at the first (left)
1013 encounter of delim:
1014 1st would stay in "this",
1015 2nd part will be returned
1016 as a new string!
1017 */
1018 GStr result;
1019 int i=index(c);
1020 if (i>=0){
1021 result=substr(i+1);
1022 cut(i);
1023 return result;
1024 }
1025 return result;
1026 }
1027
1028 GStr GStr::splitr(const char* delim) {
1029 GStr result;
1030 int i=rindex(delim);
1031 if (i>=0){
1032 result=substr(i+strlen(delim));
1033 cut(i);
1034 return result;
1035 }
1036 return result;
1037 }
1038
1039 GStr GStr::splitr(char c) {
1040 GStr result;
1041 int i=rindex(c);
1042 if (i>=0){
1043 result=substr(i+1);
1044 cut(i);
1045 return result;
1046 }
1047 return result;
1048 }
1049
1050
1051 void GStr::startTokenize(const char* delimiter, enTokenizeMode tokenizemode) {
1052 GFREE(fTokenDelimiter);
1053 GMALLOC(fTokenDelimiter,strlen(delimiter)+1);
1054 strcpy(fTokenDelimiter, delimiter);
1055 fLastTokenStart=0;
1056 fTokenizeMode=tokenizemode;
1057 }
1058
1059 bool GStr::nextToken(GStr& token) {
1060 if (fTokenDelimiter==NULL) {
1061 GError("GStr:: no token delimiter; use StartTokenize first\n");
1062 }
1063 if (fLastTokenStart>=length()) {//no more
1064 GFREE(fTokenDelimiter);
1065 fLastTokenStart=0;
1066 return false;
1067 }
1068 int dlen=strlen(fTokenDelimiter);
1069 char* delpos=NULL; //delimiter position
1070 int tlen=0;
1071 if (fTokenizeMode==tkFullString) { //exact string as a delimiter
1072 delpos=(char*)strstr(chars()+fLastTokenStart,fTokenDelimiter);
1073 if (delpos==NULL) delpos=(char*)(chars()+length());
1074 //empty records may be returned
1075 if (chars()+fLastTokenStart == delpos) { //empty token
1076 fLastTokenStart=(delpos-chars())+dlen;
1077 token="";
1078 return true;
1079 }
1080 else {
1081 tlen=delpos-(chars()+fLastTokenStart);
1082 token.replace_data(tlen);
1083 ::memcpy(token.chrs(), &chars()[fLastTokenStart], tlen);
1084 fLastTokenStart=(delpos-chars())+dlen;
1085 return true;
1086 }
1087 }
1088 else { //tkCharSet - any character is a delimiter
1089 //empty records are never returned !
1090 if (fLastTokenStart==0) {//skip any starting delimiters
1091 delpos=(char*)chars();
1092 while (*delpos!='\0' && strchr(fTokenDelimiter, *delpos)!=NULL)
1093 delpos++;
1094 if (*delpos!='\0')
1095 fLastTokenStart = delpos-chars();
1096 else { //only delimiters here,no tokens
1097 GFREE(fTokenDelimiter);
1098 fLastTokenStart=0;
1099 return false;
1100 }
1101 }
1102 //now fLastTokenStart is on a non-delimiter char
1103 //GMessage("String at fLastTokenStart=%d is %s\n", fLastTokenStart, delpos);
1104 char* token_end=NULL;
1105 delpos=(char*)strpbrk(chars()+fLastTokenStart,fTokenDelimiter);
1106 if (delpos==NULL) delpos=(char*)(chars()+length());
1107 token_end=delpos-1;
1108 while (*delpos!='\0' && strchr(fTokenDelimiter, *delpos)!=NULL)
1109 delpos++; //skip any other delimiters in the set!
1110 //now we know that delpos is on the beginning of next token
1111 tlen=(token_end-chars())-fLastTokenStart+1;
1112 if (tlen==0) {
1113 GFREE(fTokenDelimiter);
1114 fLastTokenStart=0;
1115 return false;
1116 }
1117 token.replace_data(tlen);
1118 ::memcpy(token.chrs(), &chars()[fLastTokenStart], tlen);
1119 fLastTokenStart=delpos-chars();
1120 return true;
1121 }
1122 //return true;
1123 }
1124
1125 size_t GStr::read(FILE* stream, const char* delimiter, size_t bufsize) {
1126 //read up to (and including) the given delimiter string
1127 if (readbuf==NULL) {
1128 GMALLOC(readbuf, bufsize);
1129 readbufsize=bufsize;
1130 }
1131 else if (bufsize!=readbufsize) {
1132 GFREE(readbuf);
1133 if (bufsize>0) {
1134 GMALLOC(readbuf, bufsize);
1135 }
1136 readbufsize=bufsize;
1137 }
1138 if (bufsize==0) {
1139 replace_data(0);
1140 return 0; //clear the string and free the buffer
1141 }
1142 size_t numread;
1143 size_t acc_len=0; //accumulated length
1144 int seplen=strlen(delimiter);
1145 void* p=NULL;
1146 Data *data = new_data(0);
1147 do {
1148 numread=fread(readbuf, 1, bufsize, stream);
1149 if (numread) {
1150 p=Gmemscan(readbuf, bufsize, (void*) delimiter, seplen);
1151 if (p!=NULL) {//found the delimiter
1152 //position the stream after it
1153 int l = (char*)p-(char*)readbuf;
1154 fseek(stream, l+seplen-numread, SEEK_CUR);
1155 numread=l+seplen;
1156 }
1157 else {//not found, go back if not eof
1158 if (numread==bufsize) {
1159 fseek(stream, -seplen, SEEK_CUR); //check if this works!
1160 numread-=seplen;
1161 }
1162 }
1163 if (data==&null_data) {
1164 data=new_data(numread);
1165 ::memcpy(data->chars, readbuf, numread);
1166 acc_len+=numread;
1167 }
1168 else {
1169 GREALLOC(data, sizeof(Data)+acc_len+numread);
1170 memcpy(&data->chars[acc_len], readbuf, numread);
1171 acc_len+=numread;
1172 data->length=acc_len;
1173 data->chars[acc_len]='\0';
1174 }
1175 } //if something read
1176 } while (p==NULL && numread!=0);
1177 replace_data(data);
1178 return acc_len;
1179 }
1180
1181
1182 int GStr::asInt(int base /*=10 */) {
1183 return strtol(text(), NULL, base);
1184 }
1185
1186 bool GStr::asInt(int& r, int base) {
1187 errno=0;
1188 char*endptr;
1189 long val=strtol(text(), &endptr, base);
1190 if (errno!=0) return false;
1191 if (endptr == text()) return false;
1192 /* If we got here, strtol() successfully parsed a number */
1193 r=val;
1194 return true;
1195 }
1196
1197 double GStr::asReal() {
1198 return strtod(text(), NULL);
1199 }
1200
1201 bool GStr::asReal(double& r) {
1202 errno=0;
1203 char* endptr;
1204 double val=strtod(text(), &endptr);
1205 if (errno!=0) return false;
1206 if (endptr == text()) return false; //no digits to parse
1207 r=val;
1208 return true;
1209 }
1210
1211
1212 int GStr::peelInt() const {
1213 if (is_empty()) return 0;
1214 char buf[24];
1215 bool started=false;
1216 int j=0;
1217 int i;
1218 for (i=0;i<length();i++) {
1219 if (started) {
1220 if (isdigit(my_data->chars[i])) j++; //set coord
1221 else break; //finished
1222 }
1223 else
1224 if (isdigit(my_data->chars[i])) {
1225 j++; started=true;
1226 }
1227 }
1228 if (j>0) {
1229 strncpy(buf, &my_data->chars[i-j], j);
1230 buf[j]='\0';
1231 return strtol(buf, NULL, 10);
1232 }
1233 return 0;
1234 }
1235
1236 int GStr::peelIntR() const {
1237 if (is_empty()) return 0;
1238 char buf[24];
1239 bool started=false;
1240 int j=0;
1241 int i;
1242 for (i=length()-1;i>=0;i--) {
1243 if (started) {
1244 if (isdigit(my_data->chars[i])) j++; //set length
1245 else break; //finished
1246 }
1247 else
1248 if (isdigit(my_data->chars[i])) {
1249 j++; started=true;
1250 }
1251 }
1252 if (j>0) {
1253 strncpy(buf, &my_data->chars[i+1], j);
1254 buf[j]='\0';
1255 return strtol(buf, NULL, 10);
1256 }
1257 return 0;
1258 }
1259
1260 GStr GStr::to(char c) { //return the first part up to first occurence of c
1261 int i=index(c);
1262 if (i>=0) return substr(0,i);
1263 else return (*this);
1264 }
1265 //or whole string if c not found
1266 GStr GStr::from(char c) { //same as to, but starting from the right side
1267 int i=rindex(c);
1268 if (i>=0) return substr(i+1);
1269 else return (*this);
1270 }
1271
1272 int GStr::count(char c){
1273 //return the number of occurences of char c within the string
1274 int result=0;
1275 for (int i=0;i<length();i++)
1276 if (my_data->chars[i]==c) result++;
1277 return result;
1278 }
1279
1280 //=========================================
1281
1282 void GStr::invalid_args_error(const char *fname) {
1283 GError("GStr:: %s - invalid arguments\n", fname);
1284 }
1285
1286 //****************************************************************************
1287
1288 void GStr::invalid_index_error(const char *fname) {
1289 GError("GStr:: %s - invalid index\n", fname);
1290 }
1291 //****************************************************************************