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

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