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 (7 years, 9 months ago) by gpertea
File size: 34822 byte(s)
Log Message:
wip fqtrim

Line File contents
1 //---------------------------------------------------------------------------
2 #include "GStr.h"
3 #include <stdio.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include "GBase.h"
7 #include <stdarg.h>
8 #include <errno.h>
9
10 //---------------------------------------------------------------------------
11
12 GStr::Data GStr::null_data;
13
14 //=========================================
15
16 GStr::Data * GStr::new_data(int length) {
17 //static method to return a new Data object (allocate length)
18 //content is undefined, but it's null terminated
19 if (length > 0) {
20 Data* data;
21 GMALLOC(data, sizeof(Data)+length);
22 data->ref_count = 0;
23 data->length = length;
24 data->chars[length] = '\0';
25 return data;
26 }
27 else
28 return &null_data;
29 }
30
31 GStr::Data* GStr::new_data(const char* str) {
32 //static method to return a new Data object (allocate length)
33 //as a copy of a given string
34 if (str==NULL) return &null_data;
35 int length=strlen(str);
36 if (length > 0) {
37 Data* data;
38 GMALLOC(data, sizeof(Data)+length);
39 strcpy(data->chars, str);
40 data->ref_count = 0;
41 data->length = length;
42 data->chars[length] = '\0';
43 return data;
44 }
45 else
46 return &null_data;
47 }
48
49 void GStr::replace_data(int len) {
50
51 if (len == my_data->length && my_data->ref_count <= 1)
52 return;
53
54 if (my_data != &null_data && --my_data->ref_count == 0)
55 GFREE(my_data);
56
57 if (len > 0) {
58 //my_data = (Data *) malloc(sizeof(Data) + len);
59 GMALLOC(my_data, sizeof(Data) + len);
60 my_data->ref_count = 1;
61 my_data->length = len;
62 my_data->chars[len] = '\0';
63 }
64 else
65 my_data = &null_data;
66 }
67
68 void GStr::replace_data(Data *data) {
69 if (my_data != &null_data && --my_data->ref_count == 0)
70 GFREE(my_data);
71 if (data != &null_data)
72 data->ref_count++;
73 my_data = data;
74 }
75
76 void GStr::make_unique() {//make sure it's 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 fTokenizeMode=tkCharSet;
110 fLastTokenStart=0;
111 readbuf=NULL;
112 readbufsize=0;
113 }
114
115 GStr::GStr(const GStr& s): my_data(&null_data){
116 fTokenDelimiter=NULL;
117 fTokenizeMode=tkCharSet;
118 fLastTokenStart=0;
119 readbuf=NULL;
120 readbufsize=0;
121 replace_data(s.my_data);
122 }
123
124 GStr::GStr(const char *s): my_data(&null_data) {
125 fTokenDelimiter=NULL;
126 fTokenizeMode=tkCharSet;
127 fLastTokenStart=0;
128 readbuf=NULL;
129 readbufsize=0;
130 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 fTokenizeMode=tkCharSet;
137 fLastTokenStart=0;
138 readbuf=NULL;
139 readbufsize=0;
140 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 fTokenizeMode=tkCharSet;
150 fLastTokenStart=0;
151 readbuf=NULL;
152 readbufsize=0;
153 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 fTokenizeMode=tkCharSet;
163 fLastTokenStart=0;
164 readbuf=NULL;
165 readbufsize=0;
166 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 //return (index(s, 0) == 0);
347 return ::startsWith(this->chars(), s);
348 }
349
350 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 bool GStr::contains(char c) const {
366 return (index(c, 0) >= 0);
367 }
368
369 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 for (istart=0; istart<length() && chars()[istart]==c;istart++) ;
405 if (istart==length()) {
406 make_unique(); //edit operation ahead
407 replace_data(0); //string was entirely trimmed
408 return *this;
409 }
410 for (iend=length()-1; iend>istart && chars()[iend]==c;iend--) ;
411 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 for (istart=0; istart<length() && strchr(c, chars()[istart])!=NULL ;istart++) ;
425 if (istart==length()) {
426 replace_data(0); //string was entirely trimmed
427 return *this;
428 }
429 for (iend=length()-1; iend>istart && strchr(c, chars()[iend])!=NULL;iend--) ;
430 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 for (iend=length()-1; iend>=0 && chars()[iend]==c;iend--) ;
445 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 for (iend=length()-1; iend>=0 && strchr(c,chars()[iend])!=NULL;iend--) ;
463 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 for (istart=0; istart<length() && chars()[istart]==c;istart++) ;
504 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 for (istart=0; istart<length() && strchr(c,chars()[istart])!=NULL;istart++) ;
521 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 if (len < 0 || len>length()-idx)
676 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 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
701
702 //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 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 }
1029
1030 int GStr::rindex(const char* str, int end_index) const {
1031 if (str==NULL || *str == '\0' || length()==0 || end_index>=length())
1032 return -1;
1033 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 }
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 if (delimiter) {
1105 GMALLOC(fTokenDelimiter,strlen(delimiter)+1);
1106 strcpy(fTokenDelimiter, delimiter);
1107 }
1108 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 //****************************************************************************