libStatGen Software 1
Loading...
Searching...
No Matches
StringBasics.cpp
1/*
2 * Copyright (C) 2010 Regents of the University of Michigan
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "StringBasics.h"
19#include "Error.h"
20#include "Constant.h"
21#include "MathConstant.h"
22
23#include <string.h>
24#include <ctype.h>
25#include <stdarg.h>
26#include <sstream>
27
28#define SWP(A,B) {int tmp=a; a=b; b=tmp;}
29
30#ifdef _MSC_VER
31#ifndef snprintf
32#define vsnprintf _vsnprintf
33#define snprintf _snprintf
34#endif
35#endif
36
37// If natural ordering is defined, comparisons will
38// order strings including numbers correctly
39// (eg, ... "8", "9", "10" ...) rather than using
40// ASCII ordering (... "10", "8", "9", ...)
41#define NATURAL_ORDERING 1
42
43int String::alloc = 8;
44bool String::caseSensitive = true;
45
46void String::NewString(int startsize)
47{
48 len = 0;
49 size = (startsize + alloc) / alloc * alloc;
50 buffer = new char [size];
51 buffer[0] = 0;
52}
53
54String::String(const char * s)
55{
56 int clen = s == NULL ? 0 : strlen(s);
57 NewString(clen);
58 if (clen)
59 {
60 len = clen;
61 memcpy(buffer, s, len + 1);
62 }
63}
64
65String::String(char ch, int count)
66{
67 NewString(count);
68 memset(buffer, ch, count);
69 buffer[count] = 0;
70 len = count;
71}
72
73String::String(const String & s)
74{
75 len = s.len;
76 size = (s.len + alloc) / alloc * alloc;;
77 buffer = new char [size];
78 memcpy(buffer, s.buffer, len + 1);
79}
80
81void String::Grow(int newSize)
82{
83 if (newSize >= size)
84 {
85 if ((newSize >> 1) >= size)
86 size = (newSize + alloc) / alloc * alloc;
87 else
88 {
89 size = alloc;
90 while (size <= newSize)
91 size *= 2;
92 }
93
94 char * tmp = new char [size];
95 // // len + 1 due to terminating NUL which is not counted in len
96 // memcpy(tmp, buffer, len + 1);
97 memcpy(tmp, buffer, len);
98 tmp[len] = '\0';
99 delete [] buffer;
100 buffer = tmp;
101 }
102}
103
104void String::Swap(String & s)
105{
106 char * temp = s.buffer;
107 s.buffer = buffer;
108 buffer = temp;
109
110 int swap = s.size;
111 s.size = size;
112 size = swap;
113
114 swap = s.len;
115 s.len = len;
116 len = swap;
117}
118
119String & String::Copy(const String & s)
120{
121 Grow(s.len);
122 len = s.len;
123 memcpy(buffer, s.buffer, len + 1);
124 return *this;
125}
126
127String & String::Copy(const String & s, int start, int n)
128{
129 if (s.len <= start) return Clear();
130 if (s.len < start + n) n = s.len - start;
131 Grow(n);
132 memcpy(buffer, s.buffer + start, n);
133 buffer[len = n] = 0;
134 return *this;
135}
136
137String & String::Copy(const char * s)
138{
139 if (s == NULL)
140 {
141 len = 0;
142 buffer[0] = 0;
143 }
144 else
145 {
146 int clen = strlen(s);
147 Grow(clen);
148 len = clen;
149 memcpy(buffer, s, len + 1);
150 }
151 return *this;
152}
153
154String & String::ToUpper()
155{
156 for (int i = 0; i < len; i++)
157 buffer[i] = (char) toupper(buffer[i]);
158 return *this;
159}
160
161String & String::ToLower()
162{
163 for (int i = 0; i < len; i++)
164 buffer[i] = (char) tolower(buffer[i]);
165 return *this;
166}
167
168String String::AsUpper()
169{
170 String temp;
171 temp = *this;
172 return temp.ToUpper();
173}
174
175String String::AsLower()
176{
177 String temp;
178 temp = *this;
179 return temp.ToLower();
180}
181
182String String::Capitalize()
183{
184 String temp;
185 temp = *this;
186 temp.buffer[0] = (char) toupper(temp.buffer[0]);
187 return temp;
188}
189
190String & String::operator = (const String & rhs)
191{
192 Copy(rhs);
193 return *this;
194}
195
196String & String::operator = (const char * rhs)
197{
198 Copy(rhs);
199 return * this;
200}
201
202String & String::operator += (const String & rhs)
203{
204 Grow(len + rhs.len);
205 memcpy(buffer + len, rhs.buffer, rhs.len + 1);
206 len += rhs.len;
207 return *this;
208}
209
210String & String::operator += (const char * rhs)
211{
212 if (rhs != NULL)
213 {
214 int clen = strlen(rhs);
215 Grow(len + clen);
216 memcpy(buffer + len, rhs, clen + 1);
217 len += clen;
218 }
219 return *this;
220}
221
222String String::operator + (const String & rhs) const
223{
224 String result(len + rhs.len);
225 memcpy(result.buffer, buffer, len);
226 memcpy(result.buffer + len, rhs.buffer, rhs.len + 1);
227 result.len = len + rhs.len;
228 return result;
229}
230
231String String::operator + (const char * rhs) const
232{
233 if (rhs != NULL)
234 {
235 int clen = strlen(rhs);
236 String result(len + clen);
237 memcpy(result.buffer, buffer, len);
238 memcpy(result.buffer + len, rhs, clen + 1);
239 result.len = len + clen;
240 return result;
241 }
242 return *this;
243}
244
245String & String::operator = (char ch)
246{
247 if (ch)
248 {
249 Grow(1);
250 buffer[0] = ch;
251 buffer[1] = 0;
252 len = 1;
253 }
254 else
255 len = buffer[0] = 0;
256 return *this;
257}
258
259String & String::operator += (char ch)
260{
261 if (ch)
262 {
263 Grow(len + 1);
264 buffer[len] = ch;
265 buffer[++len] = 0;
266 }
267 return *this;
268}
269
270String String::operator + (char ch) const
271{
272 String result(*this);
273 result += ch;
274 return result;
275}
276
277String & String::operator = (int rhs)
278{
279 Clear();
280
281 if (rhs < 0)
282 {
283 Add('-');
284 *this += (unsigned int) -rhs;
285 }
286 else
287 *this = (unsigned int) rhs;
288 return *this;
289}
290
291String & String::operator = (unsigned int rhs)
292{
293 Clear();
294
295 unsigned long long base = 10;
296 int digits = 1;
297
298 while (rhs >= base)
299 {
300 base *= 10;
301 digits++;
302 }
303
304 Grow(digits);
305
306 while (base /= 10)
307 {
308 char ch = char(rhs / base);
309 rhs = rhs - ch * base;
310 buffer[len++] = char(ch + '0');
311 }
312 buffer[len] = 0;
313 return *this;
314};
315
316String String::operator + (int rhs) const
317{
318 String result(*this);
319 result += rhs;
320 return result;
321};
322
323String String::operator + (unsigned int rhs) const
324{
325 String result(*this);
326 result += rhs;
327 return result;
328};
329
330String & String::operator += (int rhs)
331{
332 String temp;
333 temp = rhs;
334 return *this += temp;
335}
336
337String & String::operator += (unsigned int rhs)
338{
339 String temp;
340 temp = rhs;
341 return *this += temp;
342}
343
344String & String::operator *= (unsigned int rhs)
345{
346 if (rhs == 0)
347 Clear();
348 else
349 {
350 String original(*this);
351
352 Grow(len * rhs);
353
354 for (unsigned int i = 1; i < rhs; i++)
355 *this += original;
356 }
357 return *this;
358}
359
360String & String::operator = (double rhs)
361{
362 LockBuffer(32);
363 sprintf(buffer, "%.3f", rhs);
364 UnlockBuffer();
365 return *this;
366}
367
368String String::operator + (double rhs) const
369{
370 String result(*this);
371 result += rhs;
372 return result;
373}
374
375String & String::operator += (double rhs)
376{
377 String temp;
378 temp = rhs;
379 return *this += temp;
380}
381
382
383void String::appendFullFloat(float rhs)
384{
385 std::ostringstream os;
386 os << rhs;
387 *this += os.str().c_str();
388}
389
390char * String::LockBuffer(int min)
391{
392 if (min > 0) Grow(min);
393 return buffer;
394}
395
396String & String::UnlockBuffer()
397{
398 for (len = 0; len < size; len++)
399 if (buffer[len] == 0)
400 return *this;
401 error("BasicString - direct access overflowed buffer");
402 return *this;
403}
404
405int String::Compare(const String & s) const
406{
407 if (caseSensitive)
408 return String::FastCompare(s);
409 else
410 return String::SlowCompare(s);
411}
412
413int String::Compare(const char * s) const
414{
415 return caseSensitive ? FastCompare(s) : SlowCompare(s);
416}
417
418int String::FastCompare(const String & s) const
419{
420 for (int i = 0; i <= len; i++)
421 if (buffer[i] - s.buffer[i])
422 {
423#ifdef NATURAL_ORDERING
424 int d = i;
425 while (isdigit(buffer[d]) && isdigit(s.buffer[d]))
426 d++;
427 if (isdigit(buffer[d]))
428 return 1;
429 if (isdigit(s.buffer[d]))
430 return -1;
431#endif
432 return buffer[i] - s.buffer[i];
433 }
434 return 0;
435}
436
437int String::FastCompare(const char * s) const
438{
439 if (s == NULL)
440 return -len;
441
442 for (int i = 0; i <= len; i++)
443 if (buffer[i] - s[i])
444 {
445#ifdef NATURAL_ORDERING
446 int d = i;
447 while (isdigit(buffer[d]) && isdigit(s[d]))
448 d++;
449 if (isdigit(buffer[d]))
450 return 1;
451 if (isdigit(s[d]))
452 return -1;
453#endif
454 return buffer[i] - s[i];
455 }
456 return 0;
457}
458
459int String::SlowCompare(const String & s) const
460{
461 for (int i = 0; i <= len; i++)
462 if (toupper(buffer[i]) - toupper(s.buffer[i]))
463 {
464#ifdef NATURAL_ORDERING
465 int d = i;
466 while (isdigit(buffer[d]) && isdigit(s[d]))
467 d++;
468 if (isdigit(buffer[d]))
469 return 1;
470 if (isdigit(s.buffer[d]))
471 return -1;
472#endif
473 return toupper(buffer[i]) - toupper(s.buffer[i]);
474 }
475 return 0;
476}
477
478int String::SlowCompare(const char * s) const
479{
480 if (s == NULL)
481 return -len;
482
483 for (int i = 0; i <= len; i++)
484 if (toupper(buffer[i]) - toupper(s[i]))
485 {
486#ifdef NATURAL_ORDERING
487 int d = i;
488 while (isdigit(buffer[d]) && isdigit(s[d]))
489 d++;
490 if (isdigit(buffer[d]))
491 return 1;
492 if (isdigit(s[d]))
493 return -1;
494#endif
495 return toupper(buffer[i]) - toupper(s[i]);
496 }
497 return 0;
498}
499
500int String::ReadLine(FILE * f)
501{
502 len = 0;
503 buffer[len] = 0;
504
505 if (f == NULL) return -1;
506
507 int clen = 0;
508 char check[2] = {0, 0};
509
510 int step = 128;
511 String format("%128[^\n\r]%1[\n\r]");
512
513 int returnValue = 1;
514
515 int io = 0;
516
517 while (check[0] != '\n' && check[0] != '\r')
518 {
519 if (clen)
520 {
521 step *= 2;
522 format.printf("%%%d%s", step, "[^\n\r]%1[\n\r]");
523 }
524 clen += step;
525
526 io = fscanf(f, format, LockBuffer(clen) + len, check);
527 UnlockBuffer();
528 // Avoid getting stuck on zero length lines (system specific!)
529 if (io == 0 && check[0] != '\n' && check[0] != '\r')
530 io = fscanf(f, "%1[\n\r]", check);
531 if (io == 0 || io == EOF)
532 {
533 // Set return value to indicate error/EOF
534 returnValue = -1;
535 break;
536 }
537 }
538
539 if (check[0] == '\n') io = fscanf(f, "%*1[\r]");
540 if (check[0] == '\r') io = fscanf(f, "%*1[\n]");
541
542 return returnValue;
543}
544
545
546String & String::Read(FILE * f)
547{
548 len = 0;
549 buffer[len] = 0;
550
551 if (f == NULL) return *this;
552
553 int clen = 0;
554 char check[2] = {'G', 0};
555
556 while (strchr(WHITESPACE, check[0]) == NULL)
557 {
558 clen += READBUF;
559 int io = fscanf(f, " %" READBUFSTR "[^" WHITESPACE "]"
560 "%1[" WHITESPACE "]", LockBuffer(clen) + len, check);
561 if (io == 0 || io == EOF) break;
562 UnlockBuffer();
563 }
564
565 return *this;
566}
567
568String & String::Read()
569{
570 return Read(stdin);
571}
572
573String & String::Read(IFILE & f)
574{
575 len = 0;
576 buffer[len] = 0;
577
578 if (f == NULL) return *this;
579
580 bool leading = true;
581
582 while (true)
583 {
584 int ch = ifgetc(f);
585
586 if (ch == -1) break;
587
588 if (strchr(WHITESPACE, ch) != NULL)
589 {
590 if (leading)
591 {
592 continue;
593 }
594 else
595 {
596 break;
597 }
598 }
599
600 if (len + 1 == size)
601 Grow(len + 1);
602
603 buffer[len++] = (char) ch;
604 buffer[len] = 0;
605
606 leading = false;
607 }
608
609 return *this;
610}
611
612int String::ReadLine()
613{
614 static int last = 0;
615 int ch;
616
617 len = 0;
618 buffer[len] = 0;
619
620 while (true)
621 {
622 ch = getchar();
623
624 if (ch == EOF)
625 {
626 break;
627 }
628
629 if (ch == 10)
630 {
631 if (last == 13)
632 {
633 last = 0;
634 continue;
635 }
636 else
637 {
638 last = 10;
639 break;
640 }
641 }
642
643 if (ch == 13)
644 {
645 if (last == 10)
646 {
647 last = 0;
648 continue;
649 }
650 else
651 {
652 last = 13;
653 break;
654 }
655 }
656
657 if (len + 1 == size)
658 {
659 Grow(len + 1);
660 }
661
662 last = ch;
663 buffer[len++] = (char) last;
664 buffer[len] = 0;
665 }
666
667 if ((ch == EOF) && (len == 0))
668 {
669 // Indicate error/EOF if nothing was read.
670 return -1;
671 }
672
673 // Return success.
674 return 1;
675}
676
677
678// Read line using getc.
679
680#if defined(_WIN32)
681int String::ReadLine(IFILE & f)
682{
683 static int last = 0;
684 int ch;
685
686 len = 0;
687 buffer[len] = 0;
688
689 while (true)
690 {
691 ch = f->ifgetc();
692
693 if (ch == EOF)
694 {
695 break;
696 }
697
698 if (ch == 10)
699 {
700 if (last == 13)
701 {
702 last = 0;
703 continue;
704 }
705 else
706 {
707 last = 10;
708 break;
709 }
710 }
711
712 if (ch == 13)
713 {
714 if (last == 10)
715 {
716 last = 0;
717 continue;
718 }
719 else
720 {
721 last = 13;
722 break;
723 }
724 }
725
726 if (len + 1 == size)
727 {
728 Grow(len + 1);
729 }
730
731 last = ch;
732 buffer[len++] = (char) last;
733 buffer[len] = 0;
734 }
735
736 if ((ch == EOF) && (len == 0))
737 {
738 // Indicate error/EOF if nothing was read.
739 return -1;
740 }
741 return 1;
742}
743#else
744int String::ReadLine(IFILE & f)
745{
746 int ch;
747 char *ptr = buffer;
748 char *endBuffer = buffer + size;
749 len = 0;
750
751 while ( ((ch = f->ifgetc()) != EOF) && (ch != '\n'))
752 {
753 if (ptr >= endBuffer - 1)
754 {
755 // resize: 1 byte for the next character, 1 byte
756 // for the NUL at the end.
757 Grow(len + 2);
758 endBuffer = buffer + size;
759 ptr = buffer + len;
760 }
761
762 *ptr++ = ch;
763 len++;
764 }
765
766 // NB: assumes that buffer is always allocated.
767 buffer[len] = 0;
768
769 if ((ch == EOF) && (len == 0))
770 {
771 // Indicate error/EOF if nothing was read.
772 return -1;
773 }
774 return 1;
775}
776#endif
777
778void String::Write(FILE * f)
779{
780 fprintf(f, "%s", buffer);
781}
782
783void String::Write()
784{
785 Write(stdout);
786}
787
788void String::WriteLine()
789{
790 WriteLine(stdout);
791}
792
793void String::WriteLine(FILE * f)
794{
795 if (f == NULL) return;
796 fprintf(f, "%s\n", buffer);
797}
798
799std::ostream& operator << (std::ostream& os, const String& s)
800{
801 return os << s.c_str();
802}
803
804String String::Left(int n) const
805{
806 if (n < 0) n = 0;
807 if (len < n) n = len;
808 String result(n);
809 memcpy(result.buffer, buffer, n);
810 result.buffer[result.len = n] = 0;
811 return result;
812}
813
814String String::Right(int n) const
815{
816 if (n < 0) n = 0;
817 if (len < n) n = len;
818 String result(n);
819 memcpy(result.buffer, buffer + len - n, n);
820 result.buffer[result.len = n] = 0;
821 return result;
822}
823
824String String::SubStr(int start, int n) const
825{
826 if (start < 0)
827 {
828 n += start;
829 start = 0;
830 };
831 n = min(len - start, n);
832 n = max(n, 0);
833 String result(n);
834 if (start > len) return result;
835 memcpy(result.buffer, buffer + start, n);
836 result.buffer[result.len = n] = 0;
837 return result;
838}
839
840String String::SubStr(int start) const
841{
842 return SubStr(start, len - start);
843}
844
845String String::Mid(int start, int end) const
846{
847 return SubStr(start, end - start + 1);
848}
849
850int String::FindChar(char ch, int start) const
851{
852 return caseSensitive ? FastFindChar(ch, start) : SlowFindChar(ch, start);
853}
854
855int String::FastFindChar(char ch, int start) const
856{
857 for (; start < len; start++)
858 if (buffer[start] == ch)
859 return start;
860 return -1;
861}
862
863int String::SlowFindChar(char ch, int start) const
864{
865 ch = (char) toupper(ch);
866 for (; start < len; start++)
867 if (toupper(buffer[start]) == ch)
868 return start;
869 return -1;
870}
871
872int String::FindLastChar(char ch) const
873{
874 return caseSensitive ? FastFindLastChar(ch) : SlowFindLastChar(ch);
875}
876
877int String::FastFindLastChar(char ch) const
878{
879 for (int start = len-1; start >= 0; start--)
880 if (buffer[start] == ch)
881 return start;
882 return -1;
883}
884
885int String::SlowFindLastChar(char ch) const
886{
887 ch = (char) toupper(ch);
888 for (int start = len-1 ; start >= 0; start--)
889 if (toupper(buffer[start]) == ch)
890 return start;
891 return -1;
892}
893
894int String::Find(const String & pattern, int start) const
895{
896 return caseSensitive ? FastFind(pattern, start) : SlowFind(pattern, start);
897}
898
899// TODO -- We should have a better string search algorithm
900
901int String::FastFind(const String & pattern, int start) const
902{
903 for (int i ; start <= len - pattern.Length(); start++)
904 if (buffer[start] == pattern[0])
905 {
906 for (i = 1; i < pattern.Length(); i++)
907 if (pattern[i] != buffer[start + i])
908 break;
909 if (i == pattern.Length()) return start;
910 }
911 return -1;
912}
913
914int String::SlowFind(const String & pattern, int start) const
915{
916 int firstchar = toupper(pattern[0]);
917
918 for (int i ; start <= len - pattern.Length(); start++)
919 if (toupper(buffer[start]) == firstchar)
920 {
921 for (i = 1; i < pattern.Length(); i++)
922 if (toupper(pattern[i]) != toupper(buffer[start + i]))
923 break;
924 if (i == pattern.Length()) return start;
925 }
926 return -1;
927}
928
929int String::SetLength(int newlen)
930{
931 if (newlen > len)
932 {
933 Grow(newlen);
934 memset(buffer + len, ' ', newlen - len);
935 }
936 buffer[newlen] = 0;
937 return len = newlen;
938}
939
940String & String::Filter(const String & s)
941{
942 int to = 0;
943 for (int from = 0; from < len; from++)
944 if (s.FindChar(buffer[from]) != -1)
945 buffer[to++] = buffer[from];
946 buffer[len = to] = 0;
947 return *this;
948}
949
950String & String::Filter(const char * s)
951{
952 String filter(s);
953 return Filter(filter);
954}
955
956String & String::ExcludeCharacters(const String & s)
957{
958 int to = 0;
959 for (int from = 0; from < len; from++)
960 if (s.FindChar(buffer[from]) == -1)
961 buffer[to++] = buffer[from];
962 buffer[len = to] = 0;
963 return *this;
964}
965
966String & String::ExcludeCharacters(const char * s)
967{
968 String excluded(s);
969 return ExcludeCharacters(excluded);
970}
971
972String operator + (const char * lhs, const String & rhs)
973{
974 String result(lhs);
975 result += rhs;
976 return result;
977}
978
979String operator + (char lhs, const String & rhs)
980{
981 String result(lhs);
982 result += rhs;
983 return result;
984}
985
986String operator + (int lhs, const String & rhs)
987{
988 String result;
989 result = lhs;
990 result += rhs;
991 return result;
992}
993
994String operator + (unsigned int lhs, const String & rhs)
995{
996 String result;
997 result = lhs;
998 result += rhs;
999 return result;
1000}
1001
1002long String::AsInteger() const
1003{
1004 long returnValue = 0;
1005 if(!AsInteger(returnValue))
1006 {
1007 // This is not an integer, but nothing to do but return a value.
1008 }
1009 return(returnValue);
1010}
1011
1012
1013// Check that the string is an integer when converting it.
1014// If the entire string is an integer, return true, if not, return false.
1015bool String::AsInteger(long& intValue) const
1016{
1017 long integer = 0;
1018 int base = 10;
1019 int pos = 0;
1020 int sign = 1;
1021 bool isInt = true;
1022
1023 // If this is no value for this integer, return false.
1024 if (pos == len)
1025 {
1026 return(false);
1027 }
1028
1029 if (buffer[pos] == '-')
1030 {
1031 sign = -1, pos++;
1032 }
1033
1034 if ((len > pos + 2) && (buffer[pos] == '0') &&
1035 ((buffer[pos+1] == 'x') || (buffer[pos+1] == 'X')))
1036 {
1037 base = 16, pos += 2;
1038 }
1039
1040 // If this is no value for this integer, return false.
1041 if (pos == len)
1042 {
1043 return(false);
1044 }
1045
1046 for (; pos < len; pos++)
1047 {
1048 char digit = (char) toupper(buffer[pos]);
1049
1050 if (digit >= '0' && digit <= '9')
1051 {
1052 integer = integer * base + digit - '0';
1053 }
1054 else if (digit >= 'A' && digit <= 'F' && base == 16)
1055 {
1056 integer = integer * base + digit - 'A' + 10;
1057 }
1058 else
1059 {
1060 isInt = false;
1061 break;
1062 }
1063 }
1064
1065 intValue = sign*integer;
1066
1067 return(isInt);
1068}
1069
1070
1071// Check that the string is an integer when converting it.
1072// If the entire string is an integer, return true, if not, return false.
1073bool String::AsInteger(int& intValue) const
1074{
1075 int integer = 0;
1076 int base = 10;
1077 int pos = 0;
1078 int sign = 1;
1079 bool isInt = true;
1080
1081 // If this is no value for this integer, return false.
1082 if (pos == len)
1083 {
1084 return(false);
1085 }
1086
1087 if (buffer[pos] == '-')
1088 {
1089 sign = -1, pos++;
1090 }
1091
1092 if ((len > pos + 2) && (buffer[pos] == '0') &&
1093 ((buffer[pos+1] == 'x') || (buffer[pos+1] == 'X')))
1094 {
1095 base = 16, pos += 2;
1096 }
1097
1098 // If this is no value for this integer, return false.
1099 if (pos == len)
1100 {
1101 return(false);
1102 }
1103
1104 for (; pos < len; pos++)
1105 {
1106 char digit = (char) toupper(buffer[pos]);
1107
1108 if (digit >= '0' && digit <= '9')
1109 {
1110 integer = integer * base + digit - '0';
1111 }
1112 else if (digit >= 'A' && digit <= 'F' && base == 16)
1113 {
1114 integer = integer * base + digit - 'A' + 10;
1115 }
1116 else
1117 {
1118 isInt = false;
1119 break;
1120 }
1121 }
1122
1123 intValue = sign*integer;
1124
1125 return(isInt);
1126}
1127
1128
1129String & String::Invert()
1130{
1131 for (int i = 0, j = len - 1; i < j; i++, j--)
1132 {
1133 char tmp = buffer[i];
1134 buffer[i] = buffer[j];
1135 buffer[j] = tmp;
1136 }
1137 return *this;
1138}
1139
1140String String::RightToLeft()
1141{
1142 String result(*this);
1143 result.Invert();
1144 return result;
1145}
1146
1147String & String::Invert(const String & s)
1148{
1149 Copy(s);
1150 return Invert();
1151}
1152
1153int String::CompareToStem(const String & stem) const
1154{
1155 if (caseSensitive)
1156 return String::FastCompareToStem(stem);
1157 else
1158 return String::SlowCompareToStem(stem);
1159}
1160
1161int String::FastCompareToStem(const String & stem) const
1162{
1163 for (int i = 0; i < stem.len; i++)
1164 if (buffer[i] - stem.buffer[i])
1165 {
1166#ifdef NATURAL_ORDERING
1167 int d = i;
1168 while (isdigit(buffer[d]) && isdigit(stem.buffer[d]) && d < stem.len)
1169 d++;
1170 if (isdigit(buffer[d]) && d < stem.len)
1171 return 1;
1172 if (isdigit(stem.buffer[d]))
1173 return -1;
1174#endif
1175 return buffer[i] - stem.buffer[i];
1176 }
1177 return 0;
1178}
1179
1180int String::SlowCompareToStem(const String & stem) const
1181{
1182 for (int i = 0; i < stem.len; i++)
1183 if (toupper(buffer[i]) - toupper(stem.buffer[i]))
1184 {
1185#ifdef NATURAL_ORDERING
1186 int d = i;
1187 while (isdigit(buffer[d]) && isdigit(stem.buffer[d]) && d < stem.len)
1188 d++;
1189 if (isdigit(buffer[d]) && d < stem.len)
1190 return 1;
1191 if (isdigit(stem.buffer[d]))
1192 return -1;
1193#endif
1194 return toupper(buffer[i]) - toupper(stem.buffer[i]);
1195 }
1196 return 0;
1197}
1198
1199int String::CompareToStem(const char * stem) const
1200{
1201 if (caseSensitive)
1202 return String::FastCompareToStem(stem);
1203 else
1204 return String::SlowCompareToStem(stem);
1205}
1206
1207int String::FastCompareToStem(const char * stem) const
1208{
1209 for (int i = 0; stem[i] != 0; i++)
1210 if (buffer[i] - stem[i])
1211 return buffer[i] - stem[i];
1212 return 0;
1213}
1214
1215int String::SlowCompareToStem(const char * stem) const
1216{
1217 for (int i = 0; stem[i] != 0; i++)
1218 if (toupper(buffer[i]) - toupper(stem[i]))
1219 return toupper(buffer[i]) - toupper(stem[i]);
1220 return 0;
1221}
1222
1223int String::MatchesBeginningOf(const String & stem) const
1224{
1225 if (caseSensitive)
1226 return String::FastMatchesBeginningOf(stem);
1227 else
1228 return String::SlowMatchesBeginningOf(stem);
1229}
1230
1231int String::FastMatchesBeginningOf(const String & stem) const
1232{
1233 for (int i = 0; i < len; i++)
1234 if (buffer[i] - stem.buffer[i])
1235 return buffer[i] - stem.buffer[i];
1236 return 0;
1237}
1238
1239int String::SlowMatchesBeginningOf(const String & stem) const
1240{
1241 for (int i = 0; i < len; i++)
1242 if (toupper(buffer[i]) - toupper(stem.buffer[i]))
1243 return toupper(buffer[i]) - toupper(stem.buffer[i]);
1244 return 0;
1245}
1246
1247int String::MatchesBeginningOf(const char * stem) const
1248{
1249 if (caseSensitive)
1250 return String::FastMatchesBeginningOf(stem);
1251 else
1252 return String::SlowMatchesBeginningOf(stem);
1253}
1254
1255int String::FastMatchesBeginningOf(const char * stem) const
1256{
1257 for (int i = 0; i < len; i++)
1258 if (buffer[i] - stem[i])
1259 return buffer[i] - stem[i];
1260 return 0;
1261}
1262
1263int String::SlowMatchesBeginningOf(const char * stem) const
1264{
1265 for (int i = 0; i < len; i++)
1266 if (toupper(buffer[i]) - toupper(stem[i]))
1267 return toupper(buffer[i]) - toupper(stem[i]);
1268 return 0;
1269}
1270
1271String & String::Trim(char character)
1272{
1273 int first = 0;
1274 while (buffer[first] && buffer[first] == character)
1275 first++;
1276
1277 int last = len - 1;
1278 while (last >= 0 && buffer[last] == character)
1279 last--;
1280
1281 int out = 0;
1282 while (first <= last)
1283 buffer[out++] = buffer[first++];
1284
1285 buffer[len = out] = 0;
1286
1287 return *this;
1288}
1289
1290String & String::Trim()
1291{
1292 int first = 0;
1293 while (buffer[first] && isspace(buffer[first]))
1294 first++;
1295
1296 int last = len - 1;
1297 while (last >= 0 && isspace(buffer[last]))
1298 last--;
1299
1300 int out = 0;
1301 while (first <= last)
1302 buffer[out++] = buffer[first++];
1303
1304 buffer[len = out] = 0;
1305
1306 return *this;
1307}
1308
1309vector<String> *String::Split(char splitChar)
1310{
1311 vector<String> *result = new vector<String>;
1312 String word;
1313
1314 for (int i = 0; i<Length(); i++)
1315 {
1316 if ((*this)[i]==splitChar)
1317 {
1318 result->push_back(word);
1319 word.Clear();
1320 }
1321 else
1322 word.Add((*this)[i]);
1323 }
1324 if (word.Length()>0) result->push_back(word);
1325 return result;
1326}
1327
1328
1329#define VSNPRINTF_NOT_CHECKED 0
1330#define VSNPRINTF_IS_OK 1
1331#define VSNPRINTF_NOT_OK 2
1332
1333int String::vsnprintfChecked = 0;
1334
1335int String::printf(const char * format, ...)
1336{
1337 va_list ap;
1338 va_start(ap, format);
1339
1340 vprintf(format, ap);
1341
1342 va_end(ap);
1343 return len;
1344}
1345
1346int String::catprintf(const char * format, ...)
1347{
1348 va_list ap;
1349 va_start(ap, format);
1350
1351 vcatprintf(format, ap);
1352
1353 va_end(ap);
1354 return len;
1355}
1356
1357int String::vprintf(const char * format, va_list ap)
1358{
1359 check_vsnprintf();
1360
1361 while (true)
1362 {
1363 int bytes_needed;
1364#ifdef va_copy
1365 va_list arguments;
1366 va_copy(arguments, ap);
1367#else
1368 va_list & arguments = ap;
1369#endif
1370
1371 if (vsnprintfChecked == VSNPRINTF_IS_OK)
1372 bytes_needed = vsnprintf(buffer, size, format, arguments);
1373 else
1374 bytes_needed = my_vsnprintf(buffer, size, format, arguments);
1375
1376#ifdef va_copy
1377 va_end(arguments);
1378#endif
1379
1380 if (bytes_needed >= size)
1381 Grow(bytes_needed);
1382 else if (bytes_needed == -1)
1383 Grow(size * 2);
1384 else
1385 {
1386 return len = bytes_needed;
1387 }
1388 }
1389}
1390
1391void String::check_vsnprintf()
1392{
1393 if (vsnprintfChecked == VSNPRINTF_NOT_CHECKED)
1394 {
1395 char temp[100];
1396
1397 memset(temp, 0, 100);
1398 int check = snprintf(temp, 5, "%5s", "VSNPRINTF");
1399
1400 if (temp[6] != 0 || temp[7] != 0 || (check != 9 && check != -1))
1401 /*
1402 error("This program requires a working version of vsnprintf\n"
1403 "However, vsnprintf in the current library seems buggy\n\n"
1404 "Recompiling this program with the -D__REPLACE_SNPRINTF__ flag\n"
1405 "may solve this problem.\n\n");
1406 */
1407 vsnprintfChecked = VSNPRINTF_NOT_OK;
1408 else
1409 vsnprintfChecked = VSNPRINTF_IS_OK;
1410 }
1411}
1412
1413int String::vcatprintf(const char * format, va_list ap)
1414{
1415 check_vsnprintf();
1416
1417 if (len == size)
1418 Grow(size * 2);
1419
1420 while (true)
1421 {
1422 int bytes_needed;
1423#ifdef va_copy
1424 va_list arguments;
1425 va_copy(arguments, ap);
1426#else
1427 va_list & arguments = ap;
1428#endif
1429
1430 if (vsnprintfChecked == VSNPRINTF_IS_OK)
1431 bytes_needed = len + vsnprintf(buffer + len, size - len, format, arguments);
1432 else
1433 bytes_needed = len + my_vsnprintf(buffer + len, size - len, format, arguments);
1434
1435#ifdef va_copy
1436 va_end(arguments);
1437#endif
1438
1439 if (bytes_needed >= size)
1440 Grow(bytes_needed);
1441 else if (bytes_needed < len)
1442 Grow(size * 2);
1443 else
1444 {
1445 return len = bytes_needed;
1446 }
1447 }
1448}
1449
1450FILE * String::my_vsnprintf_file = NULL;
1451
1452int String::my_vsnprintf(char * buffer, int bufsize, const char * format, va_list args)
1453{
1454 if (my_vsnprintf_file == NULL)
1455 {
1456 my_vsnprintf_file = tmpfile();
1457 atexit(my_vsnprintf_close_file);
1458 }
1459
1460 rewind(my_vsnprintf_file);
1461
1462 int len = vfprintf(my_vsnprintf_file, format, args);
1463
1464 rewind(my_vsnprintf_file);
1465
1466 if (len < bufsize)
1467 buffer[bufsize = len] = 0;
1468 int numRead = fread(buffer, 1, bufsize, my_vsnprintf_file);
1469 if(numRead != bufsize)
1470 {
1471 std::cerr
1472 << "Warning, StringBasics failed reading stream in my_vsnprintf\n";
1473 }
1474 return len;
1475}
1476
1477int String::my_snprintf(char * buffer, int bufsize, const char * format, ...)
1478{
1479 va_list ap;
1480 va_start(ap, format);
1481
1482 int bytes = my_vsnprintf(buffer, bufsize, format, ap);
1483
1484 va_end(ap);
1485
1486 return bytes;
1487}
1488
1489void String::my_vsnprintf_close_file()
1490{
1491 fclose(my_vsnprintf_file);
1492}
1493
1494bool String::IsNumber()
1495{
1496 int pos = 0;
1497 bool digits = false;
1498
1499 // Skip leading sign
1500 if (buffer[pos] == '-' || buffer[pos] == '+')
1501 pos++;
1502
1503 // Check integer portion
1504 while (buffer[pos] >= '0' && buffer[pos] <= '9')
1505 pos++, digits = true;
1506
1507 // Skip decimal point
1508 if (buffer[pos] == '.')
1509 {
1510 pos++;
1511
1512 // Check fractional portion
1513 while (buffer[pos] >= '0' && buffer[pos] <= '9')
1514 pos++, digits = true;
1515 }
1516
1517 if (!digits) return false;
1518
1519 // Check exponent
1520 if (buffer[pos] == 'E' || buffer[pos] == 'e')
1521 {
1522 pos++;
1523
1524 // Skip leading sign
1525 if (buffer[pos] == '-' || buffer[pos] == '+')
1526 pos++;
1527
1528 digits = false;
1529
1530 // Check exponent digits
1531 while (buffer[pos] >= '0' && buffer[pos] <= '9')
1532 pos++, digits = true;
1533 }
1534
1535 return (pos == len) && digits;
1536}
1537
1538void String::Fill(char ch, int length)
1539{
1540 if (length >= 0)
1541 SetLength(length);
1542
1543 for (int i = 0; i < len; i++)
1544 buffer[i] = ch;
1545}
1546
1547String & String::Reverse()
1548{
1549 for (int i = 0, j = len - 1; i < j; i++, j--)
1550 {
1551 int tmp = buffer[i];
1552 buffer[i] = buffer[j];
1553 buffer[j] = tmp;
1554 }
1555
1556 return *this;
1557}
1558
1559// String::LeftClip() trims the string so only characters after clipPoint remain
1560
1561String & String::LeftClip(int clipAmount)
1562{
1563 if (clipAmount == 0)
1564 return *this;
1565
1566 if (clipAmount > Length())
1567 {
1568 len = 0;
1569 return *this;
1570 }
1571
1572 // Use memory move, because the two blocks can overlap
1573 memmove(buffer, buffer + clipAmount, len - clipAmount);
1574 buffer[len -= clipAmount] = 0;
1575
1576 return *this;
1577}
1578
1579String & String::RightClip(int clipAmount)
1580{
1581 if (clipAmount == 0) return *this;
1582
1583 if (clipAmount > Length())
1584 {
1585 len = 0;
1586 return *this;
1587 }
1588
1589 len -= clipAmount;
1590 buffer[len] = 0;
1591
1592 return *this;
1593}
1594
1595// Implementation of long double convertors is in flux across different platforms
1596
1597#ifdef __GNUC__
1598String::operator long double() const
1599{
1600 return strtold(buffer, NULL);
1601}
1602#else
1603#ifdef __BORLANDC__
1604String::operator long double() const
1605{
1606 return _strtold(buffer, NULL);
1607}
1608#else
1609String::operator long double() const
1610{
1611 return atof(buffer);
1612}
1613#endif
1614#endif
1615
1616
int ifgetc(IFILE file)
Get a character from the file.
Definition InputFile.h:615
Class for easily reading/writing files without having to worry about file type (uncompressed,...
Definition InputFile.h:37
int ifgetc()
Get a character from the file.
Definition InputFile.h:324