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 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     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     //****************************************************************************