ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GStr.cpp
Revision: 301
Committed: Fri Oct 26 12:44:32 2012 UTC (7 years, 2 months ago) by gpertea
File size: 34936 byte(s)
Log Message:
minor refactoring


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