1 // -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
6 // Jeffrey Stedfast (fejj@ximian.com)
8 // (C) 2001 Ximian, Inc. http://www.ximian.com
11 // FIXME: from what I gather from msdn, when a function is to return an empty string
12 // we should be returning this.Empty - some methods do this and others don't.
14 // FIXME: I didn't realise until later that `string' has a .Length method and so
15 // I am missing some proper bounds-checking in some methods. Find these
16 // instances and throw the ArgumentOutOfBoundsException at the programmer.
17 // I like pelting programmers with ArgumentOutOfBoundsException's :-)
19 // FIXME: The ToLower(), ToUpper(), and Compare(..., bool ignoreCase) methods
20 // need to be made unicode aware.
22 // FIXME: when you have a char carr[], does carr.Length include the terminating null char?
26 using System.Collections;
27 using System.Globalization;
31 public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable {
32 public static readonly string Empty = "";
37 unsafe public String (char *value)
41 // FIXME: can I do value.Length here?
45 for (i = 0; *(value + i) != '\0'; i++);
49 this.c_str = new char [this.length + 1];
50 for (i = 0; i < this.length; i++)
51 this.c_str[i] = *(value + i);
55 public String (char[] value)
59 // FIXME: value.Length includes the terminating null char?
60 this.length = value != null ? strlen (value): 0;
61 this.c_str = new char [this.length + 1];
62 for (i = 0; i < this.length; i++)
63 this.c_str[i] = value[i];
67 unsafe public String (sbyte *value)
69 // FIXME: consider unicode?
72 // FIXME: can I do value.Length here? */
76 for (i = 0; *(value + i) != '\0'; i++);
80 this.c_str = new char [this.length + 1];
81 for (i = 0; i < this.length; i++)
82 this.c_str[i] = (char) *(value + i);
86 public String (char c, int count)
91 this.c_str = new char [count + 1];
92 for (i = 0; i < count; i++)
97 unsafe public String (char *value, int startIndex, int length)
101 if (value == null && startIndex != 0 && length != 0)
102 throw new ArgumentNullException ();
104 if (startIndex < 0 || length < 0)
105 throw new ArgumentOutOfRangeException ();
107 this.length = length;
108 this.c_str = new char [length + 1];
109 for (i = 0; i < length; i++)
110 this.c_str[i] = *(value + startIndex + i);
111 this.c_str[i] = '\0';
114 public String (char[] value, int startIndex, int length)
118 if (value == null && startIndex != 0 && length != 0)
119 throw new ArgumentNullException ();
121 if (startIndex < 0 || length < 0)
122 throw new ArgumentOutOfRangeException ();
124 this.length = length;
125 this.c_str = new char [length + 1];
126 for (i = 0; i < length; i++)
127 this.c_str[i] = value[startIndex + i];
128 this.c_str[i] = '\0';
131 unsafe public String (sbyte *value, int startIndex, int length)
133 // FIXME: consider unicode?
136 if (value == null && startIndex != 0 && length != 0)
137 throw new ArgumentNullException ();
139 if (startIndex < 0 || length < 0)
140 throw new ArgumentOutOfRangeException ();
142 this.length = length;
143 this.c_str = new char [length + 1];
144 for (i = 0; i < length; i++)
145 this.c_str[i] = (char) *(value + startIndex + i);
146 this.c_str[i] = '\0';
149 unsafe public String (sbyte *value, int startIndex, int length, Encoding enc)
151 // FIXME: implement me
156 // FIXME: is there anything we need to do here?
157 /*base.Finalize ();*/
167 // FIXME: is this correct syntax??
168 public char this [int index] {
170 if (index > this.length)
171 throw new ArgumentOutOfRangeException ();
173 return this.c_str[index];
177 // Private helper methods
178 private static int strlen (char[] str)
180 // FIXME: if str.Length includes terminating null char, then return (str.Length - 1)
184 private static char tolower (char c)
186 // FIXME: make me unicode aware
187 return c >= 'A' && c <= 'Z' ? c + (char) 33 : c;
190 private static char toupper (char c)
192 // FIXME: make me unicode aware
193 return c >= 'a' && c <= 'z' ? c - (char) 33 : c;
196 private static char tolowerordinal (char c)
198 // FIXME: implement me
202 private static bool is_lwsp (char c)
204 /* this comes from the msdn docs for String.Trim() */
205 if ((c >= '\x9' && c <= '\xD') || c == '\x20' || c == '\xA0' ||
206 (c >= '\x2000' && c <= '\x200B') || c == '\x3000' || c == '\xFEFF')
212 unsafe private static int BoyerMoore (char[] haystack, char[] needle, int startIndex, int count)
214 /* (hopefully) Unicode-safe Boyer-Moore implementation */
215 uint[] skiptable = new uint[65536]; /* our unicode-safe skip-table */
217 char *ne_ptr; /* end-of-string pointers */
219 char *nc_ptr; /* compare pointers */
221 char *the_ptr; /* haystack pointers */
222 uint h_len, n_len, n, i;
224 if (haystack == null || needle == null)
225 throw new ArgumentNullException ();
228 n_len = strlen (needle);
230 /* if the search buffer is shorter than the pattern buffer, we can't match */
234 /* return an instant match if the pattern is 0-length */
238 /* set a pointer at the end of each string */
239 ne_ptr = needle + n_len - 1; /* point to char before '\0' */
240 he_ptr = haystack + startIndex + count; /* point to last valid char */
242 /* init the skip table with the pattern length */
243 for (i = 0; i < 65536; i++)
244 skiptable[i] = n_len;
246 /* set the skip value for the chars that *do* appear in the
247 * pattern buffer (needle) to the distance from the index to
248 * the end of the pattern buffer. */
249 for (nc_ptr = needle; nc_ptr < ne_ptr; nc_ptr++)
250 skiptable[(uint) *nc_ptr] = ne_ptr - nc_ptr;
252 h_ptr = haystack + startIndex;
253 while (h_len >= n_len) {
254 the_ptr = h_ptr + n_len - 1; /* set the temp haystack end pointer */
255 hc_ptr = h_ptr + n_len - 1; /* set the haystack compare pointer */
256 nc_ptr = ne_ptr; /* set the needle compare pointer */
258 /* work our way backwards until they don't match */
259 for (i = 0; nc_ptr > needle; nc_ptr--, hc_ptr--, i++)
260 if (*nc_ptr != *hc_ptr)
263 if (*nc_ptr != *hc_ptr) {
264 n = skiptable[(uint) *hc_ptr] - i;
268 return h_ptr - haystack;
275 public object Clone ()
277 // FIXME: implement me
281 public static int Compare (string strA, string strB)
285 /* Does this remind anyone of the nautilus string.h wrappers? ;-) */
291 } else if (strB == null)
294 for (i = 0; strA[i] == strB[i] && strA[i] != '\0'; i++);
296 return ((int) (strA[i] - strB[i]));
299 public static int Compare (string strA, string strB, bool ignoreCase)
304 return Compare (strA, strB);
307 * And here I thought Eazel developers were on crack...
308 * if a string is null it should pelt the programmer with
309 * ArgumentNullExceptions, damnit!
316 } else if (strB == null)
319 for (i = 0; strA[i] != '\0' && strB[i] != '\0'; i++) {
320 if (tolower (strA[i]) != tolower (strB[i]))
324 return ((int) (strA[i] - strB[i]));
327 public static int Compare (string strA, string strB, bool ignoreCase, CultureInfo culture)
329 // FIXME: implement me
333 public static int Compare (string strA, int indexA, string strB, int indexB, int length)
337 if (length < 0 || indexA < 0 || indexB < 0)
338 throw new ArgumentOutOfRangeException ();
340 if (indexA > strA.Length || indexB > strB.Length)
341 throw new ArgumentOutOfRangeException ();
343 /* And again with the ("" > null) logic... lord have mercy! */
349 } else if (strB == null)
352 for (i = 0; i < length - 1; i++) {
353 if (strA[indexA + i] != strB[indexB + i])
357 return ((int) (strA[indexA + i] - strB[indexB + i]));
360 public static int Compare (string strA, int indexA, string strB, int indexB,
361 int length, bool ignoreCase)
366 return Compare (strA, indexA, strB, indexB, length);
368 if (length < 0 || indexA < 0 || indexB < 0)
369 throw new ArgumentOutOfRangeException ();
371 if (indexA > strA.Length || indexB > strB.Length)
372 throw new ArgumentOutOfRangeException ();
374 /* When will the hurting stop!?!? */
380 } else if (strB == null)
383 for (i = 0; i < length - 1; i++) {
384 if (tolower (strA[indexA + i]) != tolower (strB[indexB + i]))
388 return ((int) (strA[indexA + i] - strB[indexB + i]));
391 public static int Compare (string strA, int indexA, string strB, int indexB,
392 int length, bool ignoreCase, CultureInfo culture)
395 throw new ArgumentNullException ();
397 if (length < 0 || indexA < 0 || indexB < 0)
398 throw new ArgumentOutOfRangeException ();
400 if (indexA > strA.Length || indexB > strB.Length)
401 throw new ArgumentOutOfRangeException ();
403 /* I can't take it anymore! */
409 } else if (strB == null)
411 // FIXME: implement me
415 public static int CompareOrdinal (string strA, string strB)
419 /* Please God, make it stop! */
425 } else if (strB == null)
428 for (i = 0; strA[i] != '\0'; i++) {
431 cA = tolowerordinal (strA[i]);
432 cB = tolowerordinal (strB[i]);
438 return ((int) (strA[i] - strB[i]));
441 public static int CompareOrdinal (string strA, int indexA, string strB, int indexB,
446 if (length < 0 || indexA < 0 || indexB < 0)
447 throw new ArgumentOutOfRangeException ();
455 } else if (strB == null)
458 for (i = 0; i < length; i++) {
461 cA = tolowerordinal (strA[indexA + i]);
462 cB = tolowerordinal (strB[indexB + i]);
468 return ((int) (strA[indexA + i] - strB[indexB + i]));
471 public int CompareTo (object obj)
473 return Compare (this, obj == null ? null : obj.ToString ());
476 public int CompareTo (string str)
478 return Compare (this, str);
481 public static string Concat (object arg)
483 return Concat (this, arg ? arg.ToString () : String.Empty);
486 public static string Concat (params object[] args)
493 throw new ArgumentNullException ();
495 strings = new string [args.Length];
497 foreach (object arg in args) {
498 /* use Empty for each null argument */
500 strings[i] = String.Empty;
502 strings[i] = arg.ToString ();
503 len += strings[i].Length;
509 str = new string [len + 1];
511 for (int j = 0; j < strings.Length; j++)
512 for (int k = 0; k < strings[j].Length; k++)
513 str[i++] = strings[j][k];
519 public static string Concat (params string[] values)
525 throw new ArgumentNullException ();
528 foreach (string value in values)
529 len += value ? value.Length : 0;
534 str = new string [len + 1];
536 foreach (string value in values) {
540 for (int j = 0; j < value.Length; j++)
548 public static string Concat (object arg0, object arg1)
550 string str0 = arg0 ? arg0.ToString () : String.Empty;
551 string str1 = arg1 ? arg1.ToString () : String.Empty;
553 return Concat (str0, str1);
556 public static string Concat (string str0, string str1)
564 str1 == String.Empty;
566 len = str0.Length + str1.Length;
570 concat = new string [len + 1];
571 for (i = 0; i < str0.Length; i++)
573 for (j = 0 ; j < str1.Length; j++)
574 concat[i + j] = str1[j];
580 public static string Concat (object arg0, object arg1, object arg2)
582 string str0 = arg0 ? arg0.ToString () : String.Empty;
583 string str1 = arg1 ? arg1.ToString () : String.Empty;
584 string str2 = arg2 ? arg2.ToString () : String.Empty;
586 return Concat (str0, str1, str2);
589 public static string Concat (string str0, string str1, string str2)
601 len = str0.Length + str1.Length + str2.Length;
605 concat = new string [len + 1];
606 for (i = 0; i < str0.Length; i++)
608 for (j = 0; j < str1.Length; j++)
609 concat[i + j] = str1[j];
610 for (k = 0; k < str2.Length; k++)
611 concat[i + j + k] = str2[k];
617 public static string Concat (string str0, string str1, string str2, string str3)
631 len = str0.Length + str1.Length + str2.Length + str3.Length;
635 concat = new string [len + 1];
636 for (i = 0; i < str0.Length; i++)
638 for (j = 0; j < str1.Length; j++)
639 concat[i + j] = str1[j];
640 for (k = 0; k < str2.Length; k++)
641 concat[i + j + k] = str2[k];
642 for (l = 0; l < str3.Length; l++)
643 concat[i + j + k + l] = str3[l];
649 public static string Copy (string str)
652 throw new ArgumentNullException ();
654 return new String (str);
657 public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
659 // LAMESPEC: should I null-terminate?
662 if (destination == null)
663 throw new ArgumentNullException ();
665 if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
666 throw new ArgumentOutOfRangeException ();
668 if (sourceIndex + count > this.length)
669 throw new ArgumentOutOfRangeException ();
671 if (destinationIndex + count > destination.Length)
672 throw new ArgumentOutOfRangeException ();
674 for (i = 0; i < count; i++)
675 destination[destinationIndex + i] = this.c_str[sourceIndex + i];
678 public bool EndsWith (string value)
680 bool endswith = true;
684 throw new ArgumentNullException ();
686 start = this.length - value.Length;
690 for (i = start; i < this.length && endswith; i++)
691 endswith = this.c_str[i] == value[i - start];
696 public override bool Equals (object obj)
698 if (!(obj is String))
701 return this == (String) obj;
704 public bool Equals (string value)
706 return this == value;
709 public static bool Equals (string a, string b)
714 public static string Format (string format, object arg0)
716 // FIXME: implement me
720 public static string Format (string format, params object[] args)
722 // FIXME: implement me
726 public static string Format (IFormatProvider provider, string format, params object[] args)
728 // FIXME: implement me
732 public static string Format (string format, object arg0, object arg1)
734 // FIXME: implement me
738 public static string Format (string format, object arg0, object arg1, object arg2)
740 // FIXME: implement me
744 //public CharEnumerator GetEnumerator ()
745 public IEnumerator GetEnumerator ()
747 // FIXME: implement me
751 public override int GetHashCode ()
753 // FIXME: implement me
757 public new Type GetType ()
759 // FIXME: implement me
763 public TypeCode GetTypeCode ()
765 // FIXME: implement me
769 public int IndexOf (char value)
771 return IndexOf (value, 0, this.length);
774 public int IndexOf (string value)
776 return IndexOf (value, 0, this.length);
779 public int IndexOf (char value, int startIndex)
781 return IndexOf (value, startIndex, this.length - startIndex);
784 public int IndexOf (string value, int startIndex)
786 return IndexOf (value, startIndex, this.length - startIndex);
789 public int IndexOf (char value, int startIndex, int count)
793 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
794 throw new ArgumentOutOfRangeException ();
796 for (i = startIndex; i - startIndex < count; i++)
797 if (this.c_str[i] == value)
803 public int IndexOf (string value, int startIndex, int count)
805 // FIXME: Use a modified Boyer-Moore algorithm to work with unicode?
809 throw new ArgumentNullException ();
811 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
812 throw new ArgumentOutOfRangeException ();
814 for (i = startIndex; i - startIndex + value.Length <= count; ) {
815 if (this.c_str[i] == value[0]) {
819 for (j = 1; equal && value[j] != '\0'; j++) {
820 equal = this.c_str[i + j] == value[j];
821 if (this.c_str[i + j] == value[0] && nexti == 0)
839 public int IndexOfAny (char[] values)
841 return IndexOfAny (values, 0, this.length);
844 public int IndexOfAny (char[] values, int startIndex)
846 return IndexOfAny (values, startIndex, this.length - startIndex);
849 public int IndexOfAny (char[] values, int startIndex, int count)
852 throw new ArgumentNullException ();
854 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
855 throw new ArgumentOutOfRangeException ();
857 for (int i = startIndex; i < startIndex + count; i++) {
858 for (int j = 0; j < strlen (values); j++) {
859 if (this.c_str[i] == values[j])
867 public string Insert (int startIndex, string value)
873 throw new ArgumentNullException ();
875 if (startIndex < 0 || startIndex > this.length)
876 throw new ArgumentOutOfRangeException ();
878 str = new string [value.Length + this.length + 1];
879 for (i = 0; i < startIndex; i++)
880 str[i] = this.c_str[i];
881 for (j = 0; j < value.Length; j++)
882 str[i + j] = value[j];
883 for ( ; i < this.length; i++)
884 str[i + j] = this.c_str[i];
890 public static string Intern (string str)
893 throw new ArgumentNullException ();
894 // FIXME: implement me
898 public static string IsInterned (string str)
901 throw new ArgumentNullException ();
902 // FIXME: implement me
906 public static string Join (string separator, string[] value)
908 return Join (separator, value, 0, value.Length);
911 public static string Join (string separator, string[] value, int startIndex, int count)
913 // LAMESPEC: msdn doesn't specify what happens when separator is null
917 if (separator == null || value == null)
918 throw new ArgumentNullException ();
920 if (startIndex + count > value.Length)
921 throw new ArgumentOutOfRangeException ();
924 for (i = startIndex, used = 0; used < count; i++, used++) {
926 len += separator.Length;
928 len += value[i].Length;
931 // We have no elements to join?
935 str = new string [len + 1];
936 for (i = 0; i < value[startIndex].Length; i++)
937 str[i] = value[startIndex][i];
940 for (j = startIndex + 1; used < count; j++, used++) {
943 for (k = 0; k < separator.Length; k++)
944 str[i++] = separator[k];
945 for (k = 0; k < value[j].Length; k++)
946 str[i++] = value[j][k];
953 public int LastIndexOf (char value)
955 for (int i = this.length; i >= 0; i--) {
956 if (this.c_str[i] == value)
963 public int LastIndexOf (string value)
965 return LastIndexOf (value, this.length, this.length);
968 public int LastIndexOf (char value, int startIndex)
970 if (startIndex < 0 || startIndex > this.length)
971 throw new ArgumentOutOfRangeException ();
973 for (int i = startIndex; i >= 0; i--) {
974 if (this.c_str[i] == value)
981 public int LastIndexOf (string value, int startIndex)
983 return LastIndexOf (value, startIndex, this.length);
986 public int LastIndexOf (char value, int startIndex, int count)
988 if (startIndex < 0 || count < 0)
989 throw new ArgumentOutOfRangeException ();
991 if (startIndex > this.length || startIndex - count < 0)
992 throw new ArgumentOutOfRangeException ();
994 for (int i = startIndex; i >= startIndex - count; i--) {
995 if (this.c_str[i] == value)
1002 public int LastIndexOf (string value, int startIndex, int count)
1004 // LAMESPEC: currently I'm using startIndex as the 0-position in the comparison,
1005 // but maybe it's the end-position in MS's implementation?
1006 // msdn is unclear on this point. I think this is correct though.
1010 throw new ArgumentNullException ();
1012 if (startIndex < 0 || startIndex > this.length)
1013 throw new ArgumentOutOfRangeException ();
1015 if (count < 0 || startIndex - count < 0)
1016 throw new ArgumentOutOfRangeException ();
1018 if (value == String.Empty)
1021 if (startIndex + value.Length > this.length) {
1022 /* just a little optimization */
1025 start = this.length - value.Length;
1026 count -= startIndex - start;
1030 // FIXME: use a reversed-unicode-safe-Boyer-Moore?
1031 len = value.Length - 1;
1032 for (i = startIndex; i >= startIndex - count; i--) {
1033 if (this.c_str[i + len] == value[len]) {
1037 for (j = len - 1; equal && j >= 0; j--)
1038 equal = this.c_str[i + j] == value[j];
1048 public int LastIndexOfAny (char[] values)
1050 return LastIndexOfAny (values, this.length, this.length);
1053 public int LastIndexOfAny (char[] values, int startIndex)
1055 return LastIndexOfAny (values, startIndex, startIndex);
1058 public int LastIndexOfAny (char[] values, int startIndex, int count)
1063 throw new ArgumentNullException ();
1065 if (startIndex < 0 || count < 0 || startIndex - count < 0)
1066 throw new ArgumentOutOfRangeException ();
1068 for (i = startIndex; i >= startIndex - count; i--) {
1069 for (int j = 0; j < strlen (values); j++) {
1070 if (this.c_str[i] == values[j])
1078 public string PadLeft (int totalWidth)
1080 return PadLeft (totalWidth, ' ');
1083 public string PadLeft (int totalWidth, char padChar)
1089 throw new ArgumentException ();
1091 str = new string [totalWidth > this.length ? totalWidth : this.length + 1];
1092 for (i = 0; i < totalWidth - this.length; i++)
1095 for (j = 0; j < this.length; i++, j++)
1096 str[i] = this.c_str[j];
1103 public string PadRight (int totalWidth)
1105 return PadRight (totalWidth, ' ');
1108 public string PadRight (int totalWidth, char padChar)
1114 throw new ArgumentException ();
1116 str = new string [totalWidth > this.length ? totalWidth : this.length + 1];
1117 for (i = 0; i < this.length; i++)
1118 str[i] = this.c_str[i];
1120 for ( ; j < str.Length; i++)
1128 public string Remove (int startIndex, int count)
1133 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
1134 throw new ArgumentOutOfRangeException ();
1136 len = this.length - count;
1138 return String.Empty;
1140 str = new string [len + 1];
1141 for (i = 0; i < startIndex; i++)
1142 str[i] = this.c_str[i];
1143 for (j = i + count; j < this.length; j++)
1144 str[i++] = this.c_str[j];
1150 public string Replace (char oldChar, char newChar)
1155 str = new string [this.length + 1];
1156 for (i = 0; i < this.length; i++) {
1157 if (this.c_str[i] == oldChar)
1160 str[i] = this.c_str[i];
1167 public string Replace (string oldValue, string newValue)
1169 // LAMESPEC: msdn doesn't specify what to do if either args is null
1170 int index, len, i, j;
1173 if (oldValue == null || newValue == null)
1174 throw new ArgumentNullException ();
1176 // Use IndexOf in case I later rewrite it to use Boyer-Moore
1177 index = IndexOf (oldValue, 0);
1179 // This is the easy one ;-)
1180 return Substring (0, this.length);
1183 len = this.length - oldValue.Length + newValue.Length;
1185 return String.Empty;
1187 str = new string [len + 1];
1188 for (i = 0; i < index; i++)
1189 str[i] = this.c_str[i];
1190 for (j = 0; j < newValue.Length; j++)
1191 str[i++] = newValue[j];
1192 for (j = index + oldValue.Length; j < this.length; j++)
1193 str[i++] = this.c_str[j];
1199 private int splitme (char[] separators, int startIndex)
1201 /* this is basically a customized IndexOfAny() for the Split() methods */
1202 for (int i = startIndex; i < this.length; i++) {
1203 if (separators != null) {
1204 foreach (char sep in separators) {
1205 if (this.c_str[i] == sep)
1206 return i - startIndex;
1208 } else if (is_lwsp (this.c_str[i])) {
1209 return i - startIndex;
1216 public string[] Split (params char[] separator)
1220 * @separator: delimiting chars or null to split on whtspc
1222 * Returns: 1. An array consisting of a single
1223 * element (@this) if none of the delimiting
1224 * chars appear in @this. 2. An array of
1225 * substrings which are delimited by one of
1226 * the separator chars. 3. An array of
1227 * substrings separated by whitespace if
1228 * @separator is null. The Empty string should
1229 * be returned wherever 2 delimiting chars are
1232 // FIXME: would using a Queue be better?
1237 list = new ArrayList ();
1238 for (index = 0, len = 0; index < this.length; index += len + 1) {
1239 len = splitme (separator, index);
1240 len = len > -1 ? len : this.length - index;
1242 list.Add (String.Empty);
1247 str = new string [len + 1];
1248 for (i = 0; i < len; i++)
1249 str[i] = this.c_str[index + i];
1256 strings = new string [list.Count];
1257 if (list.Count == 1) {
1258 /* special case for an array holding @this */
1261 for (index = 0; index < list.Count; index++)
1262 strings[index] = (string) list[index];
1268 public string[] Split (char[] separator, int maxCount)
1270 // FIXME: what to do if maxCount <= 0?
1271 // FIXME: would using Queue be better than ArrayList?
1274 int index, len, used;
1277 list = new ArrayList ();
1278 for (index = 0, len = 0; index < this.length && used < maxCount; index += len + 1) {
1279 len = splitme (separator, index);
1280 len = len > -1 ? len : this.length - index;
1282 list.Add (String.Empty);
1287 str = new string [len + 1];
1288 for (i = 0; i < len; i++)
1289 str[i] = this.c_str[index + i];
1297 /* fit the remaining chunk of the @this into it's own element */
1298 if (index != this.length) {
1302 str = new string [this.length - index + 1];
1303 for (i = index; i < this.length; i++)
1304 str[i - index] = this.c_str[i];
1305 str[i - index] = '\0';
1310 strings = new string [list.Count];
1311 if (list.Count == 1) {
1312 /* special case for an array holding @this */
1315 for (index = 0; index < list.Count; index++)
1316 strings[index] = (string) list[index];
1322 public bool StartsWith (string value)
1324 bool startswith = true;
1328 throw new ArgumentNullException ();
1330 if (value.Length > this.length)
1333 for (i = 0; i < value.Length && startswith; i++)
1334 startswith = startswith && value[i] == this.c_str[i];
1339 public string Substring (int startIndex)
1344 if (startIndex < 0 || startIndex > this.length)
1345 throw new ArgumentOutOfRangeException ();
1347 len = this.length - startIndex;
1349 return String.Empty;
1351 str = new string [len + 1];
1352 for (i = startIndex; i < this.length; i++)
1353 str[i - startIndex] = this.c_str[i];
1359 public string Substring (int startIndex, int length)
1364 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1365 throw new ArgumentOutOfRangeException ();
1368 return String.Empty;
1370 str = new string [length + 1];
1371 for (i = startIndex; i < startIndex + length; i++)
1372 str[i - startIndex] = this.c_str[i];
1378 public bool ToBoolean (IFormatProvider provider)
1380 // FIXME: implement me
1384 public byte ToByte (IFormatProvider provider)
1386 // FIXME: implement me
1390 public char ToChar (IFormatProvider provider)
1392 // FIXME: implement me
1396 public char[] ToCharArray ()
1398 return ToCharArray (0, this.length);
1401 public char[] ToCharArray (int startIndex, int length)
1406 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1407 throw new ArgumentOutOfRangeException ();
1409 chars = new char [length + 1];
1410 for (i = startIndex, i < length; i++)
1411 chars[i - startIndex] = this.c_str[i];
1413 chars[length] = '\0';
1418 public DateTime ToDateTime (IFormatProvider provider)
1420 // FIXME: implement me
1424 public decimal ToDecimal (IFormatProvider provider)
1426 // FIXME: implement me
1430 public double ToDouble (IFormatProvider provider)
1432 // FIXME: implement me
1436 public short ToInt16 (IFormatProvider provider)
1438 // FIXME: implement me
1442 public int ToInt32 (IFormatProvider provider)
1444 // FIXME: implement me
1448 public long ToInt64 (IFormatProvider provider)
1450 // FIXME: implement me
1454 public string ToLower ()
1459 str = new string [this.length + 1];
1460 for (i = 0; i < this.length; i++)
1461 str[i] = tolower (this.c_str[i]);
1467 public string ToLower (CultureInfo culture)
1469 // FIXME: implement me
1473 public sbyte ToSByte (IFormatProvider provider)
1475 // FIXME: implement me
1479 public float ToSingle (IFormatProvider provider)
1481 // FIXME: implement me
1485 public override string ToString ()
1487 return Substring (0, this.length);
1490 public string ToString (IFormatProvider format)
1492 // FIXME: implement me
1496 public object ToType (Type conversionType, IFormatProvider provider)
1498 // FIXME: implement me
1502 public ushort ToUInt16 (IFormatProvider provider)
1504 // FIXME: implement me
1508 public uint ToUInt32 (IFormatProvider provider)
1510 // FIXME: implement me
1514 public ulong ToUInt64 (IFormatProvider provider)
1516 // FIXME: implement me
1520 public string ToUpper ()
1525 str = new string [this.length + 1];
1526 for (i = 0; i < this.length; i++)
1527 str[i] = toupper (this.c_str[i]);
1533 public string ToUpper (CultureInfo culture)
1535 // FIXME: implement me
1539 public string Trim ()
1544 public string Trim (params char[] trimChars)
1550 for (begin = 0; matches && begin < this.length; begin++) {
1551 if (trimChars != null) {
1553 foreach (char c in trimChars)
1554 matches = this.c_str[begin] == c;
1556 matches = is_lwsp (this.c_str[begin]);
1561 for (end = this.length; end > begin; end--) {
1562 if (trimChars != null) {
1564 foreach (char c in trimChars)
1565 matches = this.c_str[end] == c;
1567 matches = is_lwsp (this.c_str[end]);
1572 return String.Empty;
1574 return Substring (begin, end - begin);
1577 public string TrimEnd (params char[] trimChars)
1579 bool matches = true;
1582 for (end = this.length; end > 0; end--) {
1583 if (trimChars != null) {
1585 foreach (char c in trimChars)
1586 matches = this.c_str[end] == c;
1588 matches = is_lwsp (this.c_str[end]);
1593 return String.Empty;
1595 return Substring (0, end);
1598 public string TrimStart (params char[] trimChars)
1600 bool matches = true;
1603 for (begin = 0; matches && begin < this.length; begin++) {
1604 if (trimChars != null) {
1606 foreach (char c in trimChars)
1607 matches = this.c_str[begin] == c;
1609 matches = is_lwsp (this.c_str[begin]);
1613 if (begin == this.length)
1614 return String.Empty;
1616 return Substring (begin, this.length - begin);
1620 public static bool operator ==(string a, string b)
1625 public static bool operator !=(string a, string b)