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 tolowerordinal (char c)
186 // FIXME: implement me
190 private static bool is_lwsp (char c)
192 /* this comes from the msdn docs for String.Trim() */
193 if ((c >= '\x9' && c <= '\xD') || c == '\x20' || c == '\xA0' ||
194 (c >= '\x2000' && c <= '\x200B') || c == '\x3000' || c == '\xFEFF')
200 unsafe private static int BoyerMoore (char[] haystack, char[] needle, int startIndex, int count)
202 /* (hopefully) Unicode-safe Boyer-Moore implementation */
203 uint[] skiptable = new uint[65536]; /* our unicode-safe skip-table */
205 char *ne_ptr; /* end-of-string pointers */
207 char *nc_ptr; /* compare pointers */
209 char *the_ptr; /* haystack pointers */
210 int h_len, n_len, n, i;
212 if (haystack == null || needle == null)
213 throw new ArgumentNullException ();
216 n_len = strlen (needle);
218 /* if the search buffer is shorter than the pattern buffer, we can't match */
222 /* return an instant match if the pattern is 0-length */
226 /* set a pointer at the end of each string */
227 ne_ptr = needle + n_len - 1; /* point to char before '\0' */
228 he_ptr = haystack + startIndex + count; /* point to last valid char */
230 /* init the skip table with the pattern length */
231 for (i = 0; i < 65536; i++)
232 skiptable[i] = n_len;
234 /* set the skip value for the chars that *do* appear in the
235 * pattern buffer (needle) to the distance from the index to
236 * the end of the pattern buffer. */
237 for (nc_ptr = needle; nc_ptr < ne_ptr; nc_ptr++)
238 skiptable[(uint) *nc_ptr] = ne_ptr - nc_ptr;
240 h_ptr = haystack + startIndex;
241 while (h_len >= n_len) {
242 the_ptr = h_ptr + n_len - 1; /* set the temp haystack end pointer */
243 hc_ptr = h_ptr + n_len - 1; /* set the haystack compare pointer */
244 nc_ptr = ne_ptr; /* set the needle compare pointer */
246 /* work our way backwards until they don't match */
247 for (i = 0; nc_ptr > needle; nc_ptr--, hc_ptr--, i++)
248 if (*nc_ptr != *hc_ptr)
251 if (*nc_ptr != *hc_ptr) {
252 n = skiptable[(uint) *hc_ptr] - i;
256 return h_ptr - haystack;
263 public object Clone ()
265 // FIXME: implement me
269 public static int Compare (string strA, string strB)
273 /* Does this remind anyone of the nautilus string.h wrappers? ;-) */
279 } else if (strB == null)
282 for (i = 0; strA[i] == strB[i] && strA[i] != '\0'; i++);
284 return ((int) (strA[i] - strB[i]));
287 public static int Compare (string strA, string strB, bool ignoreCase)
292 return Compare (strA, strB);
295 * And here I thought Eazel developers were on crack...
296 * if a string is null it should pelt the programmer with
297 * ArgumentNullExceptions, damnit!
304 } else if (strB == null)
307 for (i = 0; strA[i] != '\0' && strB[i] != '\0'; i++) {
308 if (Char.ToLower (strA[i]) != Char.ToLower (strB[i]))
312 return ((int) (strA[i] - strB[i]));
315 public static int Compare (string strA, string strB, bool ignoreCase, CultureInfo culture)
317 // FIXME: implement me
321 public static int Compare (string strA, int indexA, string strB, int indexB, int length)
325 if (length < 0 || indexA < 0 || indexB < 0)
326 throw new ArgumentOutOfRangeException ();
328 if (indexA > strA.Length || indexB > strB.Length)
329 throw new ArgumentOutOfRangeException ();
331 /* And again with the ("" > null) logic... lord have mercy! */
337 } else if (strB == null)
340 for (i = 0; i < length - 1; i++) {
341 if (strA[indexA + i] != strB[indexB + i])
345 return ((int) (strA[indexA + i] - strB[indexB + i]));
348 public static int Compare (string strA, int indexA, string strB, int indexB,
349 int length, bool ignoreCase)
354 return Compare (strA, indexA, strB, indexB, length);
356 if (length < 0 || indexA < 0 || indexB < 0)
357 throw new ArgumentOutOfRangeException ();
359 if (indexA > strA.Length || indexB > strB.Length)
360 throw new ArgumentOutOfRangeException ();
362 /* When will the hurting stop!?!? */
368 } else if (strB == null)
371 for (i = 0; i < length - 1; i++) {
372 if (Char.ToLower (strA[indexA + i]) != Char.ToLower (strB[indexB + i]))
376 return ((int) (strA[indexA + i] - strB[indexB + i]));
379 public static int Compare (string strA, int indexA, string strB, int indexB,
380 int length, bool ignoreCase, CultureInfo culture)
383 throw new ArgumentNullException ();
385 if (length < 0 || indexA < 0 || indexB < 0)
386 throw new ArgumentOutOfRangeException ();
388 if (indexA > strA.Length || indexB > strB.Length)
389 throw new ArgumentOutOfRangeException ();
391 /* I can't take it anymore! */
397 } else if (strB == null)
399 // FIXME: implement me
403 public static int CompareOrdinal (string strA, string strB)
407 /* Please God, make it stop! */
413 } else if (strB == null)
416 for (i = 0; strA[i] != '\0'; i++) {
419 cA = tolowerordinal (strA[i]);
420 cB = tolowerordinal (strB[i]);
426 return ((int) (strA[i] - strB[i]));
429 public static int CompareOrdinal (string strA, int indexA, string strB, int indexB,
434 if (length < 0 || indexA < 0 || indexB < 0)
435 throw new ArgumentOutOfRangeException ();
443 } else if (strB == null)
446 for (i = 0; i < length; i++) {
449 cA = tolowerordinal (strA[indexA + i]);
450 cB = tolowerordinal (strB[indexB + i]);
456 return ((int) (strA[indexA + i] - strB[indexB + i]));
459 public int CompareTo (object obj)
461 return Compare (this, obj == null ? null : obj.ToString ());
464 public int CompareTo (string str)
466 return Compare (this, str);
469 public static string Concat (object arg)
471 return arg != null ? arg.ToString () : String.Empty;
474 public static string Concat (params object[] args)
481 throw new ArgumentNullException ();
483 strings = new string [args.Length];
486 foreach (object arg in args) {
487 /* use Empty for each null argument */
489 strings[i] = String.Empty;
491 strings[i] = arg.ToString ();
492 len += strings[i].Length;
499 str = new char [len + 1];
501 for (int j = 0; j < strings.Length; j++)
502 for (int k = 0; k < strings[j].Length; k++)
503 str[i++] = strings[j][k];
506 return new String (str);
509 public static string Concat (params string[] values)
515 throw new ArgumentNullException ();
518 foreach (string value in values)
519 len += value != null ? value.Length : 0;
524 str = new char [len + 1];
526 foreach (string value in values) {
530 for (int j = 0; j < value.Length; j++)
535 return new String (str);
538 public static string Concat (object arg0, object arg1)
540 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
541 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
543 return Concat (str0, str1);
546 public static string Concat (string str0, string str1)
556 len = str0.Length + str1.Length;
560 concat = new char [len + 1];
561 for (i = 0; i < str0.Length; i++)
563 for (j = 0 ; j < str1.Length; j++)
564 concat[i + j] = str1[j];
567 return new String (concat);
570 public static string Concat (object arg0, object arg1, object arg2)
572 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
573 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
574 string str2 = arg2 != null ? arg2.ToString () : String.Empty;
576 return Concat (str0, str1, str2);
579 public static string Concat (string str0, string str1, string str2)
591 len = str0.Length + str1.Length + str2.Length;
595 concat = new char [len + 1];
596 for (i = 0; i < str0.Length; i++)
598 for (j = 0; j < str1.Length; j++)
599 concat[i + j] = str1[j];
600 for (k = 0; k < str2.Length; k++)
601 concat[i + j + k] = str2[k];
604 return new String (concat);
607 public static string Concat (string str0, string str1, string str2, string str3)
621 len = str0.Length + str1.Length + str2.Length + str3.Length;
625 concat = new char [len + 1];
626 for (i = 0; i < str0.Length; i++)
628 for (j = 0; j < str1.Length; j++)
629 concat[i + j] = str1[j];
630 for (k = 0; k < str2.Length; k++)
631 concat[i + j + k] = str2[k];
632 for (l = 0; l < str3.Length; l++)
633 concat[i + j + k + l] = str3[l];
636 return new String (concat);
639 public static string Copy (string str)
641 // FIXME: how do I *copy* a string if I can only have 1 of each?
643 throw new ArgumentNullException ();
648 public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
650 // LAMESPEC: should I null-terminate?
653 if (destination == null)
654 throw new ArgumentNullException ();
656 if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
657 throw new ArgumentOutOfRangeException ();
659 if (sourceIndex + count > this.length)
660 throw new ArgumentOutOfRangeException ();
662 if (destinationIndex + count > destination.Length)
663 throw new ArgumentOutOfRangeException ();
665 for (i = 0; i < count; i++)
666 destination[destinationIndex + i] = this.c_str[sourceIndex + i];
669 public bool EndsWith (string value)
671 bool endswith = true;
675 throw new ArgumentNullException ();
677 start = this.length - value.Length;
681 for (i = start; i < this.length && endswith; i++)
682 endswith = this.c_str[i] == value[i - start];
687 public override bool Equals (object obj)
689 if (!(obj is String))
692 return this == (String) obj;
695 public bool Equals (string value)
697 return this == value;
700 public static bool Equals (string a, string b)
705 public static string Format (string format, object arg0)
707 // FIXME: implement me
711 public static string Format (string format, params object[] args)
713 // FIXME: implement me
717 public static string Format (IFormatProvider provider, string format, params object[] args)
719 // FIXME: implement me
723 public static string Format (string format, object arg0, object arg1)
725 // FIXME: implement me
729 public static string Format (string format, object arg0, object arg1, object arg2)
731 // FIXME: implement me
735 //public CharEnumerator GetEnumerator ()
736 public IEnumerator GetEnumerator ()
738 // FIXME: implement me
742 public override int GetHashCode ()
744 // FIXME: implement me
748 public new Type GetType ()
750 // FIXME: implement me
754 public TypeCode GetTypeCode ()
756 // FIXME: implement me
760 public int IndexOf (char value)
762 return IndexOf (value, 0, this.length);
765 public int IndexOf (string value)
767 return IndexOf (value, 0, this.length);
770 public int IndexOf (char value, int startIndex)
772 return IndexOf (value, startIndex, this.length - startIndex);
775 public int IndexOf (string value, int startIndex)
777 return IndexOf (value, startIndex, this.length - startIndex);
780 public int IndexOf (char value, int startIndex, int count)
784 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
785 throw new ArgumentOutOfRangeException ();
787 for (i = startIndex; i - startIndex < count; i++)
788 if (this.c_str[i] == value)
794 public int IndexOf (string value, int startIndex, int count)
796 // FIXME: Use a modified Boyer-Moore algorithm to work with unicode?
800 throw new ArgumentNullException ();
802 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
803 throw new ArgumentOutOfRangeException ();
805 for (i = startIndex; i - startIndex + value.Length <= count; ) {
806 if (this.c_str[i] == value[0]) {
810 for (j = 1; equal && value[j] != '\0'; j++) {
811 equal = this.c_str[i + j] == value[j];
812 if (this.c_str[i + j] == value[0] && nexti == 0)
830 public int IndexOfAny (char[] values)
832 return IndexOfAny (values, 0, this.length);
835 public int IndexOfAny (char[] values, int startIndex)
837 return IndexOfAny (values, startIndex, this.length - startIndex);
840 public int IndexOfAny (char[] values, int startIndex, int count)
843 throw new ArgumentNullException ();
845 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
846 throw new ArgumentOutOfRangeException ();
848 for (int i = startIndex; i < startIndex + count; i++) {
849 for (int j = 0; j < strlen (values); j++) {
850 if (this.c_str[i] == values[j])
858 public string Insert (int startIndex, string value)
864 throw new ArgumentNullException ();
866 if (startIndex < 0 || startIndex > this.length)
867 throw new ArgumentOutOfRangeException ();
869 str = new char [value.Length + this.length + 1];
870 for (i = 0; i < startIndex; i++)
871 str[i] = this.c_str[i];
872 for (j = 0; j < value.Length; j++)
873 str[i + j] = value[j];
874 for ( ; i < this.length; i++)
875 str[i + j] = this.c_str[i];
878 return new String (str);
881 public static string Intern (string str)
884 throw new ArgumentNullException ();
885 // FIXME: implement me
889 public static string IsInterned (string str)
892 throw new ArgumentNullException ();
893 // FIXME: implement me
897 public static string Join (string separator, string[] value)
899 return Join (separator, value, 0, value.Length);
902 public static string Join (string separator, string[] value, int startIndex, int count)
904 // LAMESPEC: msdn doesn't specify what happens when separator is null
908 if (separator == null || value == null)
909 throw new ArgumentNullException ();
911 if (startIndex + count > value.Length)
912 throw new ArgumentOutOfRangeException ();
915 for (i = startIndex, used = 0; used < count; i++, used++) {
917 len += separator.Length;
919 len += value[i].Length;
922 // We have no elements to join?
926 str = new char [len + 1];
927 for (i = 0; i < value[startIndex].Length; i++)
928 str[i] = value[startIndex][i];
931 for (j = startIndex + 1; used < count; j++, used++) {
934 for (k = 0; k < separator.Length; k++)
935 str[i++] = separator[k];
936 for (k = 0; k < value[j].Length; k++)
937 str[i++] = value[j][k];
941 return new String (str);
944 public int LastIndexOf (char value)
946 for (int i = this.length; i >= 0; i--) {
947 if (this.c_str[i] == value)
954 public int LastIndexOf (string value)
956 return LastIndexOf (value, this.length, this.length);
959 public int LastIndexOf (char value, int startIndex)
961 if (startIndex < 0 || startIndex > this.length)
962 throw new ArgumentOutOfRangeException ();
964 for (int i = startIndex; i >= 0; i--) {
965 if (this.c_str[i] == value)
972 public int LastIndexOf (string value, int startIndex)
974 return LastIndexOf (value, startIndex, this.length);
977 public int LastIndexOf (char value, int startIndex, int count)
979 if (startIndex < 0 || count < 0)
980 throw new ArgumentOutOfRangeException ();
982 if (startIndex > this.length || startIndex - count < 0)
983 throw new ArgumentOutOfRangeException ();
985 for (int i = startIndex; i >= startIndex - count; i--) {
986 if (this.c_str[i] == value)
993 public int LastIndexOf (string value, int startIndex, int count)
995 // LAMESPEC: currently I'm using startIndex as the 0-position in the comparison,
996 // but maybe it's the end-position in MS's implementation?
997 // msdn is unclear on this point. I think this is correct though.
1001 throw new ArgumentNullException ();
1003 if (startIndex < 0 || startIndex > this.length)
1004 throw new ArgumentOutOfRangeException ();
1006 if (count < 0 || startIndex - count < 0)
1007 throw new ArgumentOutOfRangeException ();
1009 if (value == String.Empty)
1012 if (startIndex + value.Length > this.length) {
1013 /* just a little optimization */
1016 start = this.length - value.Length;
1017 count -= startIndex - start;
1021 // FIXME: use a reversed-unicode-safe-Boyer-Moore?
1022 len = value.Length - 1;
1023 for (i = startIndex; i >= startIndex - count; i--) {
1024 if (this.c_str[i + len] == value[len]) {
1028 for (j = len - 1; equal && j >= 0; j--)
1029 equal = this.c_str[i + j] == value[j];
1039 public int LastIndexOfAny (char[] values)
1041 return LastIndexOfAny (values, this.length, this.length);
1044 public int LastIndexOfAny (char[] values, int startIndex)
1046 return LastIndexOfAny (values, startIndex, startIndex);
1049 public int LastIndexOfAny (char[] values, int startIndex, int count)
1054 throw new ArgumentNullException ();
1056 if (startIndex < 0 || count < 0 || startIndex - count < 0)
1057 throw new ArgumentOutOfRangeException ();
1059 for (i = startIndex; i >= startIndex - count; i--) {
1060 for (int j = 0; j < strlen (values); j++) {
1061 if (this.c_str[i] == values[j])
1069 public string PadLeft (int totalWidth)
1071 return PadLeft (totalWidth, ' ');
1074 public string PadLeft (int totalWidth, char padChar)
1080 throw new ArgumentException ();
1082 str = new char [totalWidth > this.length ? totalWidth : this.length + 1];
1083 for (i = 0; i < totalWidth - this.length; i++)
1086 for (j = 0; j < this.length; i++, j++)
1087 str[i] = this.c_str[j];
1091 return new String (str);
1094 public string PadRight (int totalWidth)
1096 return PadRight (totalWidth, ' ');
1099 public string PadRight (int totalWidth, char padChar)
1105 throw new ArgumentException ();
1107 str = new char [totalWidth > this.length ? totalWidth : this.length + 1];
1108 for (i = 0; i < this.length; i++)
1109 str[i] = this.c_str[i];
1111 for ( ; i < str.Length; i++)
1116 return new String (str);
1119 public string Remove (int startIndex, int count)
1124 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
1125 throw new ArgumentOutOfRangeException ();
1127 len = this.length - count;
1129 return String.Empty;
1131 str = new char [len + 1];
1132 for (i = 0; i < startIndex; i++)
1133 str[i] = this.c_str[i];
1134 for (j = i + count; j < this.length; j++)
1135 str[i++] = this.c_str[j];
1138 return new String (str);
1141 public string Replace (char oldChar, char newChar)
1146 str = new char [this.length + 1];
1147 for (i = 0; i < this.length; i++) {
1148 if (this.c_str[i] == oldChar)
1151 str[i] = this.c_str[i];
1155 return new String (str);
1158 public string Replace (string oldValue, string newValue)
1160 // LAMESPEC: msdn doesn't specify what to do if either args is null
1161 int index, len, i, j;
1164 if (oldValue == null || newValue == null)
1165 throw new ArgumentNullException ();
1167 // Use IndexOf in case I later rewrite it to use Boyer-Moore
1168 index = IndexOf (oldValue, 0);
1170 // This is the easy one ;-)
1171 return Substring (0, this.length);
1174 len = this.length - oldValue.Length + newValue.Length;
1176 return String.Empty;
1178 str = new char [len + 1];
1179 for (i = 0; i < index; i++)
1180 str[i] = this.c_str[i];
1181 for (j = 0; j < newValue.Length; j++)
1182 str[i++] = newValue[j];
1183 for (j = index + oldValue.Length; j < this.length; j++)
1184 str[i++] = this.c_str[j];
1187 return new String (str);
1190 private int splitme (char[] separators, int startIndex)
1192 /* this is basically a customized IndexOfAny() for the Split() methods */
1193 for (int i = startIndex; i < this.length; i++) {
1194 if (separators != null) {
1195 foreach (char sep in separators) {
1196 if (this.c_str[i] == sep)
1197 return i - startIndex;
1199 } else if (is_lwsp (this.c_str[i])) {
1200 return i - startIndex;
1207 public string[] Split (params char[] separator)
1211 * @separator: delimiting chars or null to split on whtspc
1213 * Returns: 1. An array consisting of a single
1214 * element (@this) if none of the delimiting
1215 * chars appear in @this. 2. An array of
1216 * substrings which are delimited by one of
1217 * the separator chars. 3. An array of
1218 * substrings separated by whitespace if
1219 * @separator is null. The Empty string should
1220 * be returned wherever 2 delimiting chars are
1223 // FIXME: would using a Queue be better?
1228 list = new ArrayList ();
1229 for (index = 0, len = 0; index < this.length; index += len + 1) {
1230 len = splitme (separator, index);
1231 len = len > -1 ? len : this.length - index;
1233 list.Add (String.Empty);
1238 str = new char [len + 1];
1239 for (i = 0; i < len; i++)
1240 str[i] = this.c_str[index + i];
1243 list.Add (new String (str));
1247 strings = new string [list.Count];
1248 if (list.Count == 1) {
1249 /* special case for an array holding @this */
1252 for (index = 0; index < list.Count; index++)
1253 strings[index] = (string) list[index];
1259 public string[] Split (char[] separator, int maxCount)
1261 // FIXME: what to do if maxCount <= 0?
1262 // FIXME: would using Queue be better than ArrayList?
1265 int index, len, used;
1268 list = new ArrayList ();
1269 for (index = 0, len = 0; index < this.length && used < maxCount; index += len + 1) {
1270 len = splitme (separator, index);
1271 len = len > -1 ? len : this.length - index;
1273 list.Add (String.Empty);
1278 str = new char [len + 1];
1279 for (i = 0; i < len; i++)
1280 str[i] = this.c_str[index + i];
1283 list.Add (new String (str));
1288 /* fit the remaining chunk of the @this into it's own element */
1289 if (index != this.length) {
1293 str = new char [this.length - index + 1];
1294 for (i = index; i < this.length; i++)
1295 str[i - index] = this.c_str[i];
1296 str[i - index] = '\0';
1298 list.Add (new String (str));
1301 strings = new string [list.Count];
1302 if (list.Count == 1) {
1303 /* special case for an array holding @this */
1306 for (index = 0; index < list.Count; index++)
1307 strings[index] = (string) list[index];
1313 public bool StartsWith (string value)
1315 bool startswith = true;
1319 throw new ArgumentNullException ();
1321 if (value.Length > this.length)
1324 for (i = 0; i < value.Length && startswith; i++)
1325 startswith = startswith && value[i] == this.c_str[i];
1330 public string Substring (int startIndex)
1335 if (startIndex < 0 || startIndex > this.length)
1336 throw new ArgumentOutOfRangeException ();
1338 len = this.length - startIndex;
1340 return String.Empty;
1342 str = new char [len + 1];
1343 for (i = startIndex; i < this.length; i++)
1344 str[i - startIndex] = this.c_str[i];
1347 return new String (str);
1350 public string Substring (int startIndex, int length)
1355 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1356 throw new ArgumentOutOfRangeException ();
1359 return String.Empty;
1361 str = new char [length + 1];
1362 for (i = startIndex; i < startIndex + length; i++)
1363 str[i - startIndex] = this.c_str[i];
1366 return new String (str);
1369 public bool ToBoolean (IFormatProvider provider)
1371 // FIXME: implement me
1375 public byte ToByte (IFormatProvider provider)
1377 // FIXME: implement me
1381 public char ToChar (IFormatProvider provider)
1383 // FIXME: implement me
1387 public char[] ToCharArray ()
1389 return ToCharArray (0, this.length);
1392 public char[] ToCharArray (int startIndex, int length)
1397 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1398 throw new ArgumentOutOfRangeException ();
1400 chars = new char [length + 1];
1401 for (i = startIndex; i < length; i++)
1402 chars[i - startIndex] = this.c_str[i];
1404 chars[length] = '\0';
1409 public DateTime ToDateTime (IFormatProvider provider)
1411 // FIXME: implement me
1415 public decimal ToDecimal (IFormatProvider provider)
1417 // FIXME: implement me
1421 public double ToDouble (IFormatProvider provider)
1423 // FIXME: implement me
1427 public short ToInt16 (IFormatProvider provider)
1429 // FIXME: implement me
1433 public int ToInt32 (IFormatProvider provider)
1435 // FIXME: implement me
1439 public long ToInt64 (IFormatProvider provider)
1441 // FIXME: implement me
1445 public string ToLower ()
1450 str = new char [this.length + 1];
1451 for (i = 0; i < this.length; i++)
1452 str[i] = Char.ToLower (this.c_str[i]);
1455 return new String (str);
1458 public string ToLower (CultureInfo culture)
1460 // FIXME: implement me
1464 public sbyte ToSByte (IFormatProvider provider)
1466 // FIXME: implement me
1470 public float ToSingle (IFormatProvider provider)
1472 // FIXME: implement me
1476 public override string ToString ()
1478 return Substring (0, this.length);
1481 public string ToString (IFormatProvider format)
1483 // FIXME: implement me
1487 public object ToType (Type conversionType, IFormatProvider provider)
1489 // FIXME: implement me
1493 public ushort ToUInt16 (IFormatProvider provider)
1495 // FIXME: implement me
1499 public uint ToUInt32 (IFormatProvider provider)
1501 // FIXME: implement me
1505 public ulong ToUInt64 (IFormatProvider provider)
1507 // FIXME: implement me
1511 public string ToUpper ()
1516 str = new char [this.length + 1];
1517 for (i = 0; i < this.length; i++)
1518 str[i] = Char.ToUpper (this.c_str[i]);
1521 return new String (str);
1524 public string ToUpper (CultureInfo culture)
1526 // FIXME: implement me
1530 public string Trim ()
1535 public string Trim (params char[] trimChars)
1541 for (begin = 0; matches && begin < this.length; begin++) {
1542 if (trimChars != null) {
1544 foreach (char c in trimChars)
1545 matches = this.c_str[begin] == c;
1547 matches = is_lwsp (this.c_str[begin]);
1552 for (end = this.length; end > begin; end--) {
1553 if (trimChars != null) {
1555 foreach (char c in trimChars)
1556 matches = this.c_str[end] == c;
1558 matches = is_lwsp (this.c_str[end]);
1563 return String.Empty;
1565 return Substring (begin, end - begin);
1568 public string TrimEnd (params char[] trimChars)
1570 bool matches = true;
1573 for (end = this.length; end > 0; end--) {
1574 if (trimChars != null) {
1576 foreach (char c in trimChars)
1577 matches = this.c_str[end] == c;
1579 matches = is_lwsp (this.c_str[end]);
1584 return String.Empty;
1586 return Substring (0, end);
1589 public string TrimStart (params char[] trimChars)
1591 bool matches = true;
1594 for (begin = 0; matches && begin < this.length; begin++) {
1595 if (trimChars != null) {
1597 foreach (char c in trimChars)
1598 matches = this.c_str[begin] == c;
1600 matches = is_lwsp (this.c_str[begin]);
1604 if (begin == this.length)
1605 return String.Empty;
1607 return Substring (begin, this.length - begin);
1611 public static bool operator ==(string a, string b)
1616 public static bool operator !=(string a, string b)