ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GStr.cpp
Revision: 109
Committed: Tue Oct 11 19:50:14 2011 UTC (8 years ago) by gpertea
File size: 34536 byte(s)
Log Message:
added GStr::reverse(), GAlnExtend stringency tweaks

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