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;
28 using System.Runtime.CompilerServices;
32 public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable {
33 public static readonly string Empty = "";
39 unsafe public String (char *value)
43 // FIXME: can I do value.Length here?
47 for (i = 0; *(value + i) != '\0'; i++);
51 this.c_str = new char [this.length + 1];
52 for (i = 0; i < this.length; i++)
53 this.c_str[i] = *(value + i);
56 public String (char[] value)
60 // FIXME: value.Length includes the terminating null char?
61 this.length = value != null ? strlen (value): 0;
62 this.c_str = new char [this.length + 1];
63 for (i = 0; i < this.length; i++)
64 this.c_str[i] = value[i];
68 unsafe public String (sbyte *value)
70 // FIXME: consider unicode?
73 // FIXME: can I do value.Length here? */
77 for (i = 0; *(value + i) != '\0'; i++);
81 this.c_str = new char [this.length + 1];
82 for (i = 0; i < this.length; i++)
83 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);
113 public String (char[] value, int startIndex, int length)
117 if (value == null && startIndex != 0 && length != 0)
118 throw new ArgumentNullException ();
120 if (startIndex < 0 || length < 0)
121 throw new ArgumentOutOfRangeException ();
123 this.length = length;
124 this.c_str = new char [length + 1];
125 for (i = 0; i < length; i++)
126 this.c_str[i] = value[startIndex + i];
129 [CLSCompliant(false)]
130 unsafe public String (sbyte *value, int startIndex, int length)
132 // FIXME: consider unicode?
135 if (value == null && startIndex != 0 && length != 0)
136 throw new ArgumentNullException ();
138 if (startIndex < 0 || length < 0)
139 throw new ArgumentOutOfRangeException ();
141 this.length = length;
142 this.c_str = new char [length + 1];
143 for (i = 0; i < length; i++)
144 this.c_str[i] = (char) *(value + startIndex + i);
147 [CLSCompliant(false)]
148 unsafe public String (sbyte *value, int startIndex, int length, Encoding enc)
150 // FIXME: implement me
155 // FIXME: is there anything we need to do here?
156 /*base.Finalize ();*/
166 // FIXME: is this correct syntax??
167 public char this [int index] {
169 if (index >= this.length)
170 throw new ArgumentOutOfRangeException ();
172 return this.c_str[index];
176 // Private helper methods
177 private static int strlen (char[] str)
179 // FIXME: if str.Length includes terminating null char, then return (str.Length - 1)
183 private static char tolowerordinal (char c)
185 // FIXME: implement me
189 private static bool is_lwsp (char c)
191 /* this comes from the msdn docs for String.Trim() */
192 if ((c >= '\x9' && c <= '\xD') || c == '\x20' || c == '\xA0' ||
193 (c >= '\x2000' && c <= '\x200B') || c == '\x3000' || c == '\xFEFF')
199 private static int BoyerMoore (char[] haystack, string needle, int startIndex, int count)
201 /* (hopefully) Unicode-safe Boyer-Moore implementation */
202 int[] skiptable = new int[65536]; /* our unicode-safe skip-table */
203 int h, n, he, ne, hc, nc, i;
205 if (haystack == null || needle == null)
206 throw new ArgumentNullException ();
208 /* if the search buffer is shorter than the pattern buffer, we can't match */
209 if (count < needle.Length)
212 /* return an instant match if the pattern is 0-length */
213 if (needle.Length == 0)
216 /* set a pointer at the end of each string */
217 ne = needle.Length - 1; /* position of char before '\0' */
218 he = startIndex + count; /* position of last valid char */
220 /* init the skip table with the pattern length */
221 for (i = 0; i < 65536; i++)
222 skiptable[i] = needle.Length;
224 /* set the skip value for the chars that *do* appear in the
225 * pattern buffer (needle) to the distance from the index to
226 * the end of the pattern buffer. */
227 for (nc = 0; nc < ne; nc++)
228 skiptable[(int) needle[nc]] = ne - nc;
231 while (count >= needle.Length) {
232 hc = h + needle.Length - 1; /* set the haystack compare pointer */
233 nc = ne; /* set the needle compare pointer */
235 /* work our way backwards until they don't match */
236 for (i = 0; nc > 0; nc--, hc--, i++)
237 if (needle[nc] != haystack[hc])
240 if (needle[nc] != haystack[hc]) {
241 n = skiptable[(int) haystack[hc]] - i;
252 public object Clone ()
254 // FIXME: implement me
258 public static int Compare (string strA, string strB)
267 } else if (strB == null)
270 min = strA.Length < strB.Length ? strA.Length : strB.Length;
272 for (i = 0; strA[i] == strB[i] && i < min; i++);
274 return ((int) (strA[i] - strB[i]));
277 public static int Compare (string strA, string strB, bool ignoreCase)
282 return Compare (strA, strB);
285 * And here I thought Eazel developers were on crack...
286 * if a string is null it should pelt the programmer with
287 * ArgumentNullExceptions, damnit!
294 } else if (strB == null)
297 min = strA.Length < strB.Length ? strA.Length : strB.Length;
299 for (i = 0; i < min; i++) {
300 if (Char.ToLower (strA[i]) != Char.ToLower (strB[i]))
304 return ((int) (strA[i] - strB[i]));
307 public static int Compare (string strA, string strB, bool ignoreCase, CultureInfo culture)
309 // FIXME: implement me
313 public static int Compare (string strA, int indexA, string strB, int indexB, int length)
317 if (length < 0 || indexA < 0 || indexB < 0)
318 throw new ArgumentOutOfRangeException ();
320 if (indexA > strA.Length || indexB > strB.Length)
321 throw new ArgumentOutOfRangeException ();
323 /* And again with the ("" > null) logic... lord have mercy! */
329 } else if (strB == null)
332 for (i = 0; i < length - 1; i++) {
333 if (strA[indexA + i] != strB[indexB + i])
337 return ((int) (strA[indexA + i] - strB[indexB + i]));
340 public static int Compare (string strA, int indexA, string strB, int indexB,
341 int length, bool ignoreCase)
346 return Compare (strA, indexA, strB, indexB, length);
348 if (length < 0 || indexA < 0 || indexB < 0)
349 throw new ArgumentOutOfRangeException ();
351 if (indexA > strA.Length || indexB > strB.Length)
352 throw new ArgumentOutOfRangeException ();
354 /* When will the hurting stop!?!? */
360 } else if (strB == null)
363 for (i = 0; i < length - 1; i++) {
364 if (Char.ToLower (strA[indexA + i]) != Char.ToLower (strB[indexB + i]))
368 return ((int) (strA[indexA + i] - strB[indexB + i]));
371 public static int Compare (string strA, int indexA, string strB, int indexB,
372 int length, bool ignoreCase, CultureInfo culture)
375 throw new ArgumentNullException ();
377 if (length < 0 || indexA < 0 || indexB < 0)
378 throw new ArgumentOutOfRangeException ();
380 if (indexA > strA.Length || indexB > strB.Length)
381 throw new ArgumentOutOfRangeException ();
383 /* I can't take it anymore! */
389 } else if (strB == null)
392 // FIXME: implement me
396 public static int CompareOrdinal (string strA, string strB)
400 /* Please God, make it stop! */
406 } else if (strB == null)
409 for (i = 0; i < strA.Length && i < strB.Length; i++) {
412 cA = tolowerordinal (strA[i]);
413 cB = tolowerordinal (strB[i]);
419 return ((int) (strA[i] - strB[i]));
422 public static int CompareOrdinal (string strA, int indexA, string strB, int indexB,
427 if (length < 0 || indexA < 0 || indexB < 0)
428 throw new ArgumentOutOfRangeException ();
435 } else if (strB == null)
438 for (i = 0; i < length; i++) {
441 cA = tolowerordinal (strA[indexA + i]);
442 cB = tolowerordinal (strB[indexB + i]);
448 return ((int) (strA[indexA + i] - strB[indexB + i]));
451 public int CompareTo (object obj)
453 return Compare (this, obj == null ? null : obj.ToString ());
456 public int CompareTo (string str)
458 return Compare (this, str);
461 public static string Concat (object arg)
463 return arg != null ? arg.ToString () : String.Empty;
466 public static string Concat (params object[] args)
473 throw new ArgumentNullException ();
475 strings = new string [args.Length];
478 foreach (object arg in args) {
479 /* use Empty for each null argument */
481 strings[i] = String.Empty;
483 strings[i] = arg.ToString ();
484 len += strings[i].Length;
491 str = new char [len];
493 for (int j = 0; j < strings.Length; j++)
494 for (int k = 0; k < strings[j].Length; k++)
495 str[i++] = strings[j][k];
497 return new String (str);
500 public static string Concat (params string[] values)
506 throw new ArgumentNullException ();
509 foreach (string value in values)
510 len += value != null ? value.Length : 0;
515 str = new char [len];
517 foreach (string value in values) {
521 for (int j = 0; j < value.Length; j++)
525 return new String (str);
528 public static string Concat (object arg0, object arg1)
530 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
531 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
533 return Concat (str0, str1);
536 public static string Concat (string str0, string str1)
546 len = str0.Length + str1.Length;
550 concat = new char [len];
551 for (i = 0; i < str0.Length; i++)
553 for (j = 0 ; j < str1.Length; j++)
554 concat[i + j] = str1[j];
556 return new String (concat);
559 public static string Concat (object arg0, object arg1, object arg2)
561 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
562 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
563 string str2 = arg2 != null ? arg2.ToString () : String.Empty;
565 return Concat (str0, str1, str2);
568 public static string Concat (string str0, string str1, string str2)
580 len = str0.Length + str1.Length + str2.Length;
584 concat = new char [len];
585 for (i = 0; i < str0.Length; i++)
587 for (j = 0; j < str1.Length; j++)
588 concat[i + j] = str1[j];
589 for (k = 0; k < str2.Length; k++)
590 concat[i + j + k] = str2[k];
592 return new String (concat);
595 public static string Concat (string str0, string str1, string str2, string str3)
609 len = str0.Length + str1.Length + str2.Length + str3.Length;
613 concat = new char [len];
614 for (i = 0; i < str0.Length; i++)
616 for (j = 0; j < str1.Length; j++)
617 concat[i + j] = str1[j];
618 for (k = 0; k < str2.Length; k++)
619 concat[i + j + k] = str2[k];
620 for (l = 0; l < str3.Length; l++)
621 concat[i + j + k + l] = str3[l];
623 return new String (concat);
626 public static string Copy (string str)
628 // FIXME: how do I *copy* a string if I can only have 1 of each?
630 throw new ArgumentNullException ();
635 public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
637 // LAMESPEC: should I null-terminate?
640 if (destination == null)
641 throw new ArgumentNullException ();
643 if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
644 throw new ArgumentOutOfRangeException ();
646 if (sourceIndex + count > this.length)
647 throw new ArgumentOutOfRangeException ();
649 if (destinationIndex + count > destination.Length)
650 throw new ArgumentOutOfRangeException ();
652 for (i = 0; i < count; i++)
653 destination[destinationIndex + i] = this.c_str[sourceIndex + i];
656 public bool EndsWith (string value)
658 bool endswith = true;
662 throw new ArgumentNullException ();
664 start = this.length - value.Length;
668 for (i = start; i < this.length && endswith; i++)
669 endswith = this.c_str[i] == value[i - start];
674 public override bool Equals (object obj)
676 if (!(obj is String))
679 return this == (String) obj;
682 public bool Equals (string value)
684 return this == value;
687 public static bool Equals (string a, string b)
692 public static string Format (string format, object arg0)
694 // FIXME: implement me
698 public static string Format (string format, params object[] args)
700 // FIXME: implement me
704 public static string Format (IFormatProvider provider, string format, params object[] args)
706 // FIXME: implement me
710 public static string Format (string format, object arg0, object arg1)
712 // FIXME: implement me
716 public static string Format (string format, object arg0, object arg1, object arg2)
718 // FIXME: implement me
722 //public CharEnumerator GetEnumerator ()
723 public IEnumerator GetEnumerator ()
725 // FIXME: implement me
729 public override int GetHashCode ()
731 // FIXME: implement me
735 public new Type GetType ()
737 // FIXME: implement me
741 public TypeCode GetTypeCode ()
743 // FIXME: implement me
747 public int IndexOf (char value)
749 return IndexOf (value, 0, this.length);
752 public int IndexOf (string value)
754 return IndexOf (value, 0, this.length);
757 public int IndexOf (char value, int startIndex)
759 return IndexOf (value, startIndex, this.length - startIndex);
762 public int IndexOf (string value, int startIndex)
764 return IndexOf (value, startIndex, this.length - startIndex);
767 public int IndexOf (char value, int startIndex, int count)
771 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
772 throw new ArgumentOutOfRangeException ();
774 for (i = startIndex; i - startIndex < count; i++)
775 if (this.c_str[i] == value)
781 public int IndexOf (string value, int startIndex, int count)
784 throw new ArgumentNullException ();
786 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
787 throw new ArgumentOutOfRangeException ();
789 return BoyerMoore (this.c_str, value, startIndex, count);
792 for (i = startIndex; i - startIndex + value.Length <= count; ) {
793 if (this.c_str[i] == value[0]) {
797 for (j = 1; equal && j < value.Length; j++) {
798 equal = this.c_str[i + j] == value[j];
799 if (this.c_str[i + j] == value[0] && nexti == 0)
818 public int IndexOfAny (char[] values)
820 return IndexOfAny (values, 0, this.length);
823 public int IndexOfAny (char[] values, int startIndex)
825 return IndexOfAny (values, startIndex, this.length - startIndex);
828 public int IndexOfAny (char[] values, int startIndex, int count)
831 throw new ArgumentNullException ();
833 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
834 throw new ArgumentOutOfRangeException ();
836 for (int i = startIndex; i < startIndex + count; i++) {
837 for (int j = 0; j < strlen (values); j++) {
838 if (this.c_str[i] == values[j])
846 public string Insert (int startIndex, string value)
852 throw new ArgumentNullException ();
854 if (startIndex < 0 || startIndex > this.length)
855 throw new ArgumentOutOfRangeException ();
857 str = new char [value.Length + this.length];
858 for (i = 0; i < startIndex; i++)
859 str[i] = this.c_str[i];
860 for (j = 0; j < value.Length; j++)
861 str[i + j] = value[j];
862 for ( ; i < this.length; i++)
863 str[i + j] = this.c_str[i];
865 return new String (str);
868 [MethodImplAttribute(MethodImplOptions.InternalCall)]
869 public extern static string Intern (string str);
871 [MethodImplAttribute(MethodImplOptions.InternalCall)]
872 public extern static string IsInterned (string str);
874 public static string Join (string separator, string[] value)
876 return Join (separator, value, 0, value.Length);
879 public static string Join (string separator, string[] value, int startIndex, int count)
881 // LAMESPEC: msdn doesn't specify what happens when separator is null
885 if (separator == null || value == null)
886 throw new ArgumentNullException ();
888 if (startIndex + count > value.Length)
889 throw new ArgumentOutOfRangeException ();
892 for (i = startIndex, used = 0; used < count; i++, used++) {
894 len += separator.Length;
896 len += value[i].Length;
899 // We have no elements to join?
903 str = new char [len];
904 for (i = 0; i < value[startIndex].Length; i++)
905 str[i] = value[startIndex][i];
908 for (j = startIndex + 1; used < count; j++, used++) {
911 for (k = 0; k < separator.Length; k++)
912 str[i++] = separator[k];
913 for (k = 0; k < value[j].Length; k++)
914 str[i++] = value[j][k];
917 return new String (str);
920 public int LastIndexOf (char value)
926 for (; i >= 0; i--) {
927 if (this.c_str[i] == value)
934 public int LastIndexOf (string value)
936 return LastIndexOf (value, this.length, this.length);
939 public int LastIndexOf (char value, int startIndex)
941 if (startIndex < 0 || startIndex > this.length)
942 throw new ArgumentOutOfRangeException ();
944 for (int i = startIndex; i >= 0; i--) {
945 if (this.c_str[i] == value)
952 public int LastIndexOf (string value, int startIndex)
954 return LastIndexOf (value, startIndex, this.length);
957 public int LastIndexOf (char value, int startIndex, int count)
959 if (startIndex < 0 || count < 0)
960 throw new ArgumentOutOfRangeException ();
962 if (startIndex > this.length || startIndex - count < 0)
963 throw new ArgumentOutOfRangeException ();
965 for (int i = startIndex; i >= startIndex - count; i--) {
966 if (this.c_str[i] == value)
973 public int LastIndexOf (string value, int startIndex, int count)
975 // LAMESPEC: currently I'm using startIndex as the 0-position in the comparison,
976 // but maybe it's the end-position in MS's implementation?
977 // msdn is unclear on this point. I think this is correct though.
981 throw new ArgumentNullException ();
983 if (startIndex < 0 || startIndex > this.length)
984 throw new ArgumentOutOfRangeException ();
986 if (count < 0 || startIndex - count < 0)
987 throw new ArgumentOutOfRangeException ();
989 if (value == String.Empty)
992 if (startIndex + value.Length > this.length) {
993 /* just a little optimization */
996 start = this.length - value.Length;
997 count -= startIndex - start;
1001 // FIXME: use a reversed-unicode-safe-Boyer-Moore?
1002 len = value.Length - 1;
1003 for (i = startIndex; i >= startIndex - count; i--) {
1004 if (this.c_str[i + len] == value[len]) {
1008 for (j = len - 1; equal && j >= 0; j--)
1009 equal = this.c_str[i + j] == value[j];
1019 public int LastIndexOfAny (char[] values)
1021 return LastIndexOfAny (values, this.length, this.length);
1024 public int LastIndexOfAny (char[] values, int startIndex)
1026 return LastIndexOfAny (values, startIndex, startIndex);
1029 public int LastIndexOfAny (char[] values, int startIndex, int count)
1034 throw new ArgumentNullException ();
1036 if (startIndex < 0 || count < 0 || startIndex - count < 0)
1037 throw new ArgumentOutOfRangeException ();
1039 for (i = startIndex; i >= startIndex - count; i--) {
1040 for (int j = 0; j < strlen (values); j++) {
1041 if (this.c_str[i] == values[j])
1049 public string PadLeft (int totalWidth)
1051 return PadLeft (totalWidth, ' ');
1054 public string PadLeft (int totalWidth, char padChar)
1060 throw new ArgumentException ();
1062 str = new char [totalWidth > this.length ? totalWidth : this.length];
1063 for (i = 0; i < totalWidth - this.length; i++)
1066 for (j = 0; j < this.length; i++, j++)
1067 str[i] = this.c_str[j];
1069 return new String (str);
1072 public string PadRight (int totalWidth)
1074 return PadRight (totalWidth, ' ');
1077 public string PadRight (int totalWidth, char padChar)
1083 throw new ArgumentException ();
1085 str = new char [totalWidth > this.length ? totalWidth : this.length];
1086 for (i = 0; i < this.length; i++)
1087 str[i] = this.c_str[i];
1089 for ( ; i < str.Length; i++)
1092 return new String (str);
1095 public string Remove (int startIndex, int count)
1100 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
1101 throw new ArgumentOutOfRangeException ();
1103 len = this.length - count;
1105 return String.Empty;
1107 str = new char [len];
1108 for (i = 0; i < startIndex; i++)
1109 str[i] = this.c_str[i];
1110 for (j = i + count; j < this.length; j++)
1111 str[i++] = this.c_str[j];
1113 return new String (str);
1116 public string Replace (char oldChar, char newChar)
1121 str = new char [this.length];
1122 for (i = 0; i < this.length; i++) {
1123 if (this.c_str[i] == oldChar)
1126 str[i] = this.c_str[i];
1129 return new String (str);
1132 public string Replace (string oldValue, string newValue)
1134 // LAMESPEC: msdn doesn't specify what to do if either args is null
1135 int index, len, i, j;
1138 if (oldValue == null || newValue == null)
1139 throw new ArgumentNullException ();
1141 // Use IndexOf in case I later rewrite it to use Boyer-Moore
1142 index = IndexOf (oldValue, 0);
1144 // This is the easy one ;-)
1145 return Substring (0, this.length);
1148 len = this.length - oldValue.Length + newValue.Length;
1150 return String.Empty;
1152 str = new char [len];
1153 for (i = 0; i < index; i++)
1154 str[i] = this.c_str[i];
1155 for (j = 0; j < newValue.Length; j++)
1156 str[i++] = newValue[j];
1157 for (j = index + oldValue.Length; j < this.length; j++)
1158 str[i++] = this.c_str[j];
1160 return new String (str);
1163 private int splitme (char[] separators, int startIndex)
1165 /* this is basically a customized IndexOfAny() for the Split() methods */
1166 for (int i = startIndex; i < this.length; i++) {
1167 if (separators != null) {
1168 foreach (char sep in separators) {
1169 if (this.c_str[i] == sep)
1170 return i - startIndex;
1172 } else if (is_lwsp (this.c_str[i])) {
1173 return i - startIndex;
1180 public string[] Split (params char[] separator)
1184 * @separator: delimiting chars or null to split on whtspc
1186 * Returns: 1. An array consisting of a single
1187 * element (@this) if none of the delimiting
1188 * chars appear in @this. 2. An array of
1189 * substrings which are delimited by one of
1190 * the separator chars. 3. An array of
1191 * substrings separated by whitespace if
1192 * @separator is null. The Empty string should
1193 * be returned wherever 2 delimiting chars are
1196 // FIXME: would using a Queue be better?
1201 list = new ArrayList ();
1202 for (index = 0, len = 0; index < this.length; index += len + 1) {
1203 len = splitme (separator, index);
1204 len = len > -1 ? len : this.length - index;
1206 list.Add (String.Empty);
1211 str = new char [len];
1212 for (i = 0; i < len; i++)
1213 str[i] = this.c_str[index + i];
1215 list.Add (new String (str));
1219 strings = new string [list.Count];
1220 if (list.Count == 1) {
1221 /* special case for an array holding @this */
1224 for (index = 0; index < list.Count; index++)
1225 strings[index] = (string) list[index];
1231 public string[] Split (char[] separator, int maxCount)
1233 // FIXME: what to do if maxCount <= 0?
1234 // FIXME: would using Queue be better than ArrayList?
1237 int index, len, used;
1240 list = new ArrayList ();
1241 for (index = 0, len = 0; index < this.length && used < maxCount; index += len + 1) {
1242 len = splitme (separator, index);
1243 len = len > -1 ? len : this.length - index;
1245 list.Add (String.Empty);
1250 str = new char [len];
1251 for (i = 0; i < len; i++)
1252 str[i] = this.c_str[index + i];
1254 list.Add (new String (str));
1259 /* fit the remaining chunk of the @this into it's own element */
1260 if (index != this.length) {
1264 str = new char [this.length - index];
1265 for (i = index; i < this.length; i++)
1266 str[i - index] = this.c_str[i];
1268 list.Add (new String (str));
1271 strings = new string [list.Count];
1272 if (list.Count == 1) {
1273 /* special case for an array holding @this */
1276 for (index = 0; index < list.Count; index++)
1277 strings[index] = (string) list[index];
1283 public bool StartsWith (string value)
1285 bool startswith = true;
1289 throw new ArgumentNullException ();
1291 if (value.Length > this.length)
1294 for (i = 0; i < value.Length && startswith; i++)
1295 startswith = startswith && value[i] == this.c_str[i];
1300 public string Substring (int startIndex)
1305 if (startIndex < 0 || startIndex > this.length)
1306 throw new ArgumentOutOfRangeException ();
1308 len = this.length - startIndex;
1310 return String.Empty;
1312 str = new char [len];
1313 for (i = startIndex; i < this.length; i++)
1314 str[i - startIndex] = this.c_str[i];
1316 return new String (str);
1319 public string Substring (int startIndex, int length)
1324 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1325 throw new ArgumentOutOfRangeException ();
1328 return String.Empty;
1330 str = new char [length];
1331 for (i = startIndex; i < startIndex + length; i++)
1332 str[i - startIndex] = this.c_str[i];
1334 return new String (str);
1337 public bool ToBoolean (IFormatProvider provider)
1339 // FIXME: implement me
1340 throw new NotImplementedException ();
1343 public byte ToByte (IFormatProvider provider)
1345 // FIXME: implement me
1346 throw new NotImplementedException ();
1349 public char ToChar (IFormatProvider provider)
1351 // FIXME: implement me
1352 throw new NotImplementedException ();
1355 public char[] ToCharArray ()
1357 return ToCharArray (0, this.length);
1360 public char[] ToCharArray (int startIndex, int length)
1365 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1366 throw new ArgumentOutOfRangeException ();
1368 chars = new char [length];
1369 for (i = startIndex; i < length; i++)
1370 chars[i - startIndex] = this.c_str[i];
1375 public DateTime ToDateTime (IFormatProvider provider)
1377 // FIXME: implement me
1378 // return new DateTime (0);
1379 throw new NotImplementedException ();
1382 public decimal ToDecimal (IFormatProvider provider)
1384 // FIXME: implement me
1385 throw new NotImplementedException ();
1388 public double ToDouble (IFormatProvider provider)
1390 // FIXME: implement me
1391 throw new NotImplementedException ();
1394 public short ToInt16 (IFormatProvider provider)
1396 // FIXME: implement me
1397 throw new NotImplementedException ();
1400 public int ToInt32 (IFormatProvider provider)
1402 // FIXME: implement me
1403 throw new NotImplementedException ();
1406 public long ToInt64 (IFormatProvider provider)
1408 // FIXME: implement me
1409 throw new NotImplementedException ();
1412 public string ToLower ()
1417 str = new char [this.length];
1418 for (i = 0; i < this.length; i++)
1419 str[i] = Char.ToLower (this.c_str[i]);
1421 return new String (str);
1424 public string ToLower (CultureInfo culture)
1426 // FIXME: implement me
1427 throw new NotImplementedException ();
1431 [CLSCompliant(false)]
1432 public sbyte ToSByte (IFormatProvider provider)
1434 // FIXME: implement me
1435 throw new NotImplementedException ();
1438 public float ToSingle (IFormatProvider provider)
1440 // FIXME: implement me
1441 throw new NotImplementedException ();
1444 public override string ToString ()
1446 return Substring (0, this.length);
1449 public string ToString (IFormatProvider format)
1451 // FIXME: implement me
1452 throw new NotImplementedException ();
1455 public object ToType (Type conversionType, IFormatProvider provider)
1457 // FIXME: implement me
1458 throw new NotImplementedException ();
1461 [CLSCompliant(false)]
1462 public ushort ToUInt16 (IFormatProvider provider)
1464 // FIXME: implement me
1465 throw new NotImplementedException ();
1468 [CLSCompliant(false)]
1469 public uint ToUInt32 (IFormatProvider provider)
1471 // FIXME: implement me
1472 throw new NotImplementedException ();
1475 [CLSCompliant(false)]
1476 public ulong ToUInt64 (IFormatProvider provider)
1478 // FIXME: implement me
1479 throw new NotImplementedException ();
1482 public string ToUpper ()
1487 str = new char [this.length];
1488 for (i = 0; i < this.length; i++)
1489 str[i] = Char.ToUpper (this.c_str[i]);
1491 return new String (str);
1494 public string ToUpper (CultureInfo culture)
1496 // FIXME: implement me
1497 throw new NotImplementedException ();
1500 public string Trim ()
1505 public string Trim (params char[] trimChars)
1511 for (begin = 0; matches && begin < this.length; begin++) {
1512 if (trimChars != null) {
1514 foreach (char c in trimChars) {
1515 matches = this.c_str[begin] == c;
1520 matches = is_lwsp (this.c_str[begin]);
1525 for (end = this.length-1; end > begin; end--) {
1526 if (trimChars != null) {
1528 foreach (char c in trimChars) {
1529 matches = this.c_str[end] == c;
1534 matches = is_lwsp (this.c_str[end]);
1539 return String.Empty;
1541 return Substring (begin, end - begin);
1544 public string TrimEnd (params char[] trimChars)
1546 bool matches = true;
1549 for (end = this.length; end > 0; end--) {
1550 if (trimChars != null) {
1552 foreach (char c in trimChars) {
1553 matches = this.c_str[end] == c;
1558 matches = is_lwsp (this.c_str[end]);
1563 return String.Empty;
1565 return Substring (0, end);
1568 public string TrimStart (params char[] trimChars)
1570 bool matches = true;
1573 for (begin = 0; matches && begin < this.length; begin++) {
1574 if (trimChars != null) {
1576 foreach (char c in trimChars) {
1577 matches = this.c_str[begin] == c;
1582 matches = is_lwsp (this.c_str[begin]);
1586 if (begin == this.length)
1587 return String.Empty;
1589 return Substring (begin, this.length - begin);
1593 public static bool operator ==(string a, string b)
1595 if (a.length != b.length)
1599 for (int i = 0; i < l; i++)
1600 if (a.c_str[i] != b.c_str[i])
1606 public static bool operator !=(string a, string b)