ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GStr.cpp
Revision: 174
Committed: Wed Feb 15 21:04:38 2012 UTC (12 years, 6 months ago) by gpertea
File size: 34822 byte(s)
Log Message:
wip fqtrim

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