ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GStr.cpp
Revision: 16
Committed: Mon Jul 18 20:56:02 2011 UTC (8 years, 3 months ago) by gpertea
File size: 34296 byte(s)
Log Message:
sync with local source

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