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 = "";
38 unsafe public String (char *value)
42 // FIXME: can I do value.Length here?
46 for (i = 0; *(value + i) != '\0'; i++);
50 this.c_str = new char [this.length + 1];
51 for (i = 0; i < this.length; i++)
52 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);
87 public String (char c, int count)
92 this.c_str = new char [count + 1];
93 for (i = 0; i < count; i++)
98 unsafe public String (char *value, int startIndex, int length)
102 if (value == null && startIndex != 0 && length != 0)
103 throw new ArgumentNullException ();
105 if (startIndex < 0 || length < 0)
106 throw new ArgumentOutOfRangeException ();
108 this.length = length;
109 this.c_str = new char [length + 1];
110 for (i = 0; i < length; i++)
111 this.c_str[i] = *(value + startIndex + i);
112 this.c_str[i] = '\0';
115 public String (char[] value, int startIndex, int length)
119 if (value == null && startIndex != 0 && length != 0)
120 throw new ArgumentNullException ();
122 if (startIndex < 0 || length < 0)
123 throw new ArgumentOutOfRangeException ();
125 this.length = length;
126 this.c_str = new char [length + 1];
127 for (i = 0; i < length; i++)
128 this.c_str[i] = value[startIndex + i];
129 this.c_str[i] = '\0';
132 unsafe public String (sbyte *value, int startIndex, int length)
134 // FIXME: consider unicode?
137 if (value == null && startIndex != 0 && length != 0)
138 throw new ArgumentNullException ();
140 if (startIndex < 0 || length < 0)
141 throw new ArgumentOutOfRangeException ();
143 this.length = length;
144 this.c_str = new char [length + 1];
145 for (i = 0; i < length; i++)
146 this.c_str[i] = (char) *(value + startIndex + i);
147 this.c_str[i] = '\0';
150 unsafe public String (sbyte *value, int startIndex, int length, Encoding enc)
152 // FIXME: implement me
157 // FIXME: is there anything we need to do here?
158 /*base.Finalize ();*/
168 // FIXME: is this correct syntax??
169 public char this [int index] {
171 if (index > this.length)
172 throw new ArgumentOutOfRangeException ();
174 return this.c_str[index];
178 // Private helper methods
179 private static int strlen (char[] str)
181 // FIXME: if str.Length includes terminating null char, then return (str.Length - 1)
185 private static char tolowerordinal (char c)
187 // FIXME: implement me
191 private static bool is_lwsp (char c)
193 /* this comes from the msdn docs for String.Trim() */
194 if ((c >= '\x9' && c <= '\xD') || c == '\x20' || c == '\xA0' ||
195 (c >= '\x2000' && c <= '\x200B') || c == '\x3000' || c == '\xFEFF')
201 private static int BoyerMoore (char[] haystack, string needle, int startIndex, int count)
203 /* (hopefully) Unicode-safe Boyer-Moore implementation */
204 int[] skiptable = new int[65536]; /* our unicode-safe skip-table */
205 int h, n, he, ne, hc, nc, i;
207 if (haystack == null || needle == null)
208 throw new ArgumentNullException ();
210 /* if the search buffer is shorter than the pattern buffer, we can't match */
211 if (count < needle.Length)
214 /* return an instant match if the pattern is 0-length */
215 if (needle.Length == 0)
218 /* set a pointer at the end of each string */
219 ne = needle.Length - 1; /* position of char before '\0' */
220 he = startIndex + count; /* position of last valid char */
222 /* init the skip table with the pattern length */
223 for (i = 0; i < 65536; i++)
224 skiptable[i] = needle.Length;
226 /* set the skip value for the chars that *do* appear in the
227 * pattern buffer (needle) to the distance from the index to
228 * the end of the pattern buffer. */
229 for (nc = 0; nc < ne; nc++)
230 skiptable[(int) needle[nc]] = ne - nc;
233 while (count >= needle.Length) {
234 hc = h + needle.Length - 1; /* set the haystack compare pointer */
235 nc = ne; /* set the needle compare pointer */
237 /* work our way backwards until they don't match */
238 for (i = 0; nc > 0; nc--, hc--, i++)
239 if (needle[nc] != haystack[hc])
242 if (needle[nc] != haystack[hc]) {
243 n = skiptable[(int) haystack[hc]] - i;
254 public object Clone ()
256 // FIXME: implement me
260 public static int Compare (string strA, string strB)
264 /* Does this remind anyone of the nautilus string.h wrappers? ;-) */
270 } else if (strB == null)
273 for (i = 0; strA[i] == strB[i] && strA[i] != '\0'; i++);
275 return ((int) (strA[i] - strB[i]));
278 public static int Compare (string strA, string strB, bool ignoreCase)
283 return Compare (strA, strB);
286 * And here I thought Eazel developers were on crack...
287 * if a string is null it should pelt the programmer with
288 * ArgumentNullExceptions, damnit!
295 } else if (strB == null)
298 for (i = 0; strA[i] != '\0' && strB[i] != '\0'; i++) {
299 if (Char.ToLower (strA[i]) != Char.ToLower (strB[i]))
303 return ((int) (strA[i] - strB[i]));
306 public static int Compare (string strA, string strB, bool ignoreCase, CultureInfo culture)
308 // FIXME: implement me
312 public static int Compare (string strA, int indexA, string strB, int indexB, int length)
316 if (length < 0 || indexA < 0 || indexB < 0)
317 throw new ArgumentOutOfRangeException ();
319 if (indexA > strA.Length || indexB > strB.Length)
320 throw new ArgumentOutOfRangeException ();
322 /* And again with the ("" > null) logic... lord have mercy! */
328 } else if (strB == null)
331 for (i = 0; i < length - 1; i++) {
332 if (strA[indexA + i] != strB[indexB + i])
336 return ((int) (strA[indexA + i] - strB[indexB + i]));
339 public static int Compare (string strA, int indexA, string strB, int indexB,
340 int length, bool ignoreCase)
345 return Compare (strA, indexA, strB, indexB, length);
347 if (length < 0 || indexA < 0 || indexB < 0)
348 throw new ArgumentOutOfRangeException ();
350 if (indexA > strA.Length || indexB > strB.Length)
351 throw new ArgumentOutOfRangeException ();
353 /* When will the hurting stop!?!? */
359 } else if (strB == null)
362 for (i = 0; i < length - 1; i++) {
363 if (Char.ToLower (strA[indexA + i]) != Char.ToLower (strB[indexB + i]))
367 return ((int) (strA[indexA + i] - strB[indexB + i]));
370 public static int Compare (string strA, int indexA, string strB, int indexB,
371 int length, bool ignoreCase, CultureInfo culture)
374 throw new ArgumentNullException ();
376 if (length < 0 || indexA < 0 || indexB < 0)
377 throw new ArgumentOutOfRangeException ();
379 if (indexA > strA.Length || indexB > strB.Length)
380 throw new ArgumentOutOfRangeException ();
382 /* I can't take it anymore! */
388 } else if (strB == null)
390 // FIXME: implement me
394 public static int CompareOrdinal (string strA, string strB)
398 /* Please God, make it stop! */
404 } else if (strB == null)
407 for (i = 0; strA[i] != '\0'; i++) {
410 cA = tolowerordinal (strA[i]);
411 cB = tolowerordinal (strB[i]);
417 return ((int) (strA[i] - strB[i]));
420 public static int CompareOrdinal (string strA, int indexA, string strB, int indexB,
425 if (length < 0 || indexA < 0 || indexB < 0)
426 throw new ArgumentOutOfRangeException ();
434 } else if (strB == null)
437 for (i = 0; i < length; i++) {
440 cA = tolowerordinal (strA[indexA + i]);
441 cB = tolowerordinal (strB[indexB + i]);
447 return ((int) (strA[indexA + i] - strB[indexB + i]));
450 public int CompareTo (object obj)
452 return Compare (this, obj == null ? null : obj.ToString ());
455 public int CompareTo (string str)
457 return Compare (this, str);
460 public static string Concat (object arg)
462 return arg != null ? arg.ToString () : String.Empty;
465 public static string Concat (params object[] args)
472 throw new ArgumentNullException ();
474 strings = new string [args.Length];
477 foreach (object arg in args) {
478 /* use Empty for each null argument */
480 strings[i] = String.Empty;
482 strings[i] = arg.ToString ();
483 len += strings[i].Length;
490 str = new char [len + 1];
492 for (int j = 0; j < strings.Length; j++)
493 for (int k = 0; k < strings[j].Length; k++)
494 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 + 1];
517 foreach (string value in values) {
521 for (int j = 0; j < value.Length; j++)
526 return new String (str);
529 public static string Concat (object arg0, object arg1)
531 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
532 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
534 return Concat (str0, str1);
537 public static string Concat (string str0, string str1)
547 len = str0.Length + str1.Length;
551 concat = new char [len + 1];
552 for (i = 0; i < str0.Length; i++)
554 for (j = 0 ; j < str1.Length; j++)
555 concat[i + j] = str1[j];
558 return new String (concat);
561 public static string Concat (object arg0, object arg1, object arg2)
563 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
564 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
565 string str2 = arg2 != null ? arg2.ToString () : String.Empty;
567 return Concat (str0, str1, str2);
570 public static string Concat (string str0, string str1, string str2)
582 len = str0.Length + str1.Length + str2.Length;
586 concat = new char [len + 1];
587 for (i = 0; i < str0.Length; i++)
589 for (j = 0; j < str1.Length; j++)
590 concat[i + j] = str1[j];
591 for (k = 0; k < str2.Length; k++)
592 concat[i + j + k] = str2[k];
595 return new String (concat);
598 public static string Concat (string str0, string str1, string str2, string str3)
612 len = str0.Length + str1.Length + str2.Length + str3.Length;
616 concat = new char [len + 1];
617 for (i = 0; i < str0.Length; i++)
619 for (j = 0; j < str1.Length; j++)
620 concat[i + j] = str1[j];
621 for (k = 0; k < str2.Length; k++)
622 concat[i + j + k] = str2[k];
623 for (l = 0; l < str3.Length; l++)
624 concat[i + j + k + l] = str3[l];
627 return new String (concat);
630 public static string Copy (string str)
632 // FIXME: how do I *copy* a string if I can only have 1 of each?
634 throw new ArgumentNullException ();
639 public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
641 // LAMESPEC: should I null-terminate?
644 if (destination == null)
645 throw new ArgumentNullException ();
647 if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
648 throw new ArgumentOutOfRangeException ();
650 if (sourceIndex + count > this.length)
651 throw new ArgumentOutOfRangeException ();
653 if (destinationIndex + count > destination.Length)
654 throw new ArgumentOutOfRangeException ();
656 for (i = 0; i < count; i++)
657 destination[destinationIndex + i] = this.c_str[sourceIndex + i];
660 public bool EndsWith (string value)
662 bool endswith = true;
666 throw new ArgumentNullException ();
668 start = this.length - value.Length;
672 for (i = start; i < this.length && endswith; i++)
673 endswith = this.c_str[i] == value[i - start];
678 public override bool Equals (object obj)
680 if (!(obj is String))
683 return this == (String) obj;
686 public bool Equals (string value)
688 return this == value;
691 public static bool Equals (string a, string b)
696 public static string Format (string format, object arg0)
698 // FIXME: implement me
702 public static string Format (string format, params object[] args)
704 // FIXME: implement me
708 public static string Format (IFormatProvider provider, string format, params object[] args)
710 // FIXME: implement me
714 public static string Format (string format, object arg0, object arg1)
716 // FIXME: implement me
720 public static string Format (string format, object arg0, object arg1, object arg2)
722 // FIXME: implement me
726 //public CharEnumerator GetEnumerator ()
727 public IEnumerator GetEnumerator ()
729 // FIXME: implement me
733 public override int GetHashCode ()
735 // FIXME: implement me
739 public new Type GetType ()
741 // FIXME: implement me
745 public TypeCode GetTypeCode ()
747 // FIXME: implement me
751 public int IndexOf (char value)
753 return IndexOf (value, 0, this.length);
756 public int IndexOf (string value)
758 return IndexOf (value, 0, this.length);
761 public int IndexOf (char value, int startIndex)
763 return IndexOf (value, startIndex, this.length - startIndex);
766 public int IndexOf (string value, int startIndex)
768 return IndexOf (value, startIndex, this.length - startIndex);
771 public int IndexOf (char value, int startIndex, int count)
775 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
776 throw new ArgumentOutOfRangeException ();
778 for (i = startIndex; i - startIndex < count; i++)
779 if (this.c_str[i] == value)
785 public int IndexOf (string value, int startIndex, int count)
790 throw new ArgumentNullException ();
792 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
793 throw new ArgumentOutOfRangeException ();
795 return BoyerMoore (this.c_str, value, startIndex, count);
797 for (i = startIndex; i - startIndex + value.Length <= count; ) {
798 if (this.c_str[i] == value[0]) {
802 for (j = 1; equal && value[j] != '\0'; j++) {
803 equal = this.c_str[i + j] == value[j];
804 if (this.c_str[i + j] == value[0] && nexti == 0)
823 public int IndexOfAny (char[] values)
825 return IndexOfAny (values, 0, this.length);
828 public int IndexOfAny (char[] values, int startIndex)
830 return IndexOfAny (values, startIndex, this.length - startIndex);
833 public int IndexOfAny (char[] values, int startIndex, int count)
836 throw new ArgumentNullException ();
838 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
839 throw new ArgumentOutOfRangeException ();
841 for (int i = startIndex; i < startIndex + count; i++) {
842 for (int j = 0; j < strlen (values); j++) {
843 if (this.c_str[i] == values[j])
851 public string Insert (int startIndex, string value)
857 throw new ArgumentNullException ();
859 if (startIndex < 0 || startIndex > this.length)
860 throw new ArgumentOutOfRangeException ();
862 str = new char [value.Length + this.length + 1];
863 for (i = 0; i < startIndex; i++)
864 str[i] = this.c_str[i];
865 for (j = 0; j < value.Length; j++)
866 str[i + j] = value[j];
867 for ( ; i < this.length; i++)
868 str[i + j] = this.c_str[i];
871 return new String (str);
874 [MethodImplAttribute(MethodImplOptions.InternalCall)]
875 public extern static string Intern (string str);
877 [MethodImplAttribute(MethodImplOptions.InternalCall)]
878 public extern static string IsInterned (string str);
880 public static string Join (string separator, string[] value)
882 return Join (separator, value, 0, value.Length);
885 public static string Join (string separator, string[] value, int startIndex, int count)
887 // LAMESPEC: msdn doesn't specify what happens when separator is null
891 if (separator == null || value == null)
892 throw new ArgumentNullException ();
894 if (startIndex + count > value.Length)
895 throw new ArgumentOutOfRangeException ();
898 for (i = startIndex, used = 0; used < count; i++, used++) {
900 len += separator.Length;
902 len += value[i].Length;
905 // We have no elements to join?
909 str = new char [len + 1];
910 for (i = 0; i < value[startIndex].Length; i++)
911 str[i] = value[startIndex][i];
914 for (j = startIndex + 1; used < count; j++, used++) {
917 for (k = 0; k < separator.Length; k++)
918 str[i++] = separator[k];
919 for (k = 0; k < value[j].Length; k++)
920 str[i++] = value[j][k];
924 return new String (str);
927 public int LastIndexOf (char value)
929 for (int i = this.length; i >= 0; i--) {
930 if (this.c_str[i] == value)
937 public int LastIndexOf (string value)
939 return LastIndexOf (value, this.length, this.length);
942 public int LastIndexOf (char value, int startIndex)
944 if (startIndex < 0 || startIndex > this.length)
945 throw new ArgumentOutOfRangeException ();
947 for (int i = startIndex; i >= 0; i--) {
948 if (this.c_str[i] == value)
955 public int LastIndexOf (string value, int startIndex)
957 return LastIndexOf (value, startIndex, this.length);
960 public int LastIndexOf (char value, int startIndex, int count)
962 if (startIndex < 0 || count < 0)
963 throw new ArgumentOutOfRangeException ();
965 if (startIndex > this.length || startIndex - count < 0)
966 throw new ArgumentOutOfRangeException ();
968 for (int i = startIndex; i >= startIndex - count; i--) {
969 if (this.c_str[i] == value)
976 public int LastIndexOf (string value, int startIndex, int count)
978 // LAMESPEC: currently I'm using startIndex as the 0-position in the comparison,
979 // but maybe it's the end-position in MS's implementation?
980 // msdn is unclear on this point. I think this is correct though.
984 throw new ArgumentNullException ();
986 if (startIndex < 0 || startIndex > this.length)
987 throw new ArgumentOutOfRangeException ();
989 if (count < 0 || startIndex - count < 0)
990 throw new ArgumentOutOfRangeException ();
992 if (value == String.Empty)
995 if (startIndex + value.Length > this.length) {
996 /* just a little optimization */
999 start = this.length - value.Length;
1000 count -= startIndex - start;
1004 // FIXME: use a reversed-unicode-safe-Boyer-Moore?
1005 len = value.Length - 1;
1006 for (i = startIndex; i >= startIndex - count; i--) {
1007 if (this.c_str[i + len] == value[len]) {
1011 for (j = len - 1; equal && j >= 0; j--)
1012 equal = this.c_str[i + j] == value[j];
1022 public int LastIndexOfAny (char[] values)
1024 return LastIndexOfAny (values, this.length, this.length);
1027 public int LastIndexOfAny (char[] values, int startIndex)
1029 return LastIndexOfAny (values, startIndex, startIndex);
1032 public int LastIndexOfAny (char[] values, int startIndex, int count)
1037 throw new ArgumentNullException ();
1039 if (startIndex < 0 || count < 0 || startIndex - count < 0)
1040 throw new ArgumentOutOfRangeException ();
1042 for (i = startIndex; i >= startIndex - count; i--) {
1043 for (int j = 0; j < strlen (values); j++) {
1044 if (this.c_str[i] == values[j])
1052 public string PadLeft (int totalWidth)
1054 return PadLeft (totalWidth, ' ');
1057 public string PadLeft (int totalWidth, char padChar)
1063 throw new ArgumentException ();
1065 str = new char [totalWidth > this.length ? totalWidth : this.length + 1];
1066 for (i = 0; i < totalWidth - this.length; i++)
1069 for (j = 0; j < this.length; i++, j++)
1070 str[i] = this.c_str[j];
1074 return new String (str);
1077 public string PadRight (int totalWidth)
1079 return PadRight (totalWidth, ' ');
1082 public string PadRight (int totalWidth, char padChar)
1088 throw new ArgumentException ();
1090 str = new char [totalWidth > this.length ? totalWidth : this.length + 1];
1091 for (i = 0; i < this.length; i++)
1092 str[i] = this.c_str[i];
1094 for ( ; i < str.Length; i++)
1099 return new String (str);
1102 public string Remove (int startIndex, int count)
1107 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
1108 throw new ArgumentOutOfRangeException ();
1110 len = this.length - count;
1112 return String.Empty;
1114 str = new char [len + 1];
1115 for (i = 0; i < startIndex; i++)
1116 str[i] = this.c_str[i];
1117 for (j = i + count; j < this.length; j++)
1118 str[i++] = this.c_str[j];
1121 return new String (str);
1124 public string Replace (char oldChar, char newChar)
1129 str = new char [this.length + 1];
1130 for (i = 0; i < this.length; i++) {
1131 if (this.c_str[i] == oldChar)
1134 str[i] = this.c_str[i];
1138 return new String (str);
1141 public string Replace (string oldValue, string newValue)
1143 // LAMESPEC: msdn doesn't specify what to do if either args is null
1144 int index, len, i, j;
1147 if (oldValue == null || newValue == null)
1148 throw new ArgumentNullException ();
1150 // Use IndexOf in case I later rewrite it to use Boyer-Moore
1151 index = IndexOf (oldValue, 0);
1153 // This is the easy one ;-)
1154 return Substring (0, this.length);
1157 len = this.length - oldValue.Length + newValue.Length;
1159 return String.Empty;
1161 str = new char [len + 1];
1162 for (i = 0; i < index; i++)
1163 str[i] = this.c_str[i];
1164 for (j = 0; j < newValue.Length; j++)
1165 str[i++] = newValue[j];
1166 for (j = index + oldValue.Length; j < this.length; j++)
1167 str[i++] = this.c_str[j];
1170 return new String (str);
1173 private int splitme (char[] separators, int startIndex)
1175 /* this is basically a customized IndexOfAny() for the Split() methods */
1176 for (int i = startIndex; i < this.length; i++) {
1177 if (separators != null) {
1178 foreach (char sep in separators) {
1179 if (this.c_str[i] == sep)
1180 return i - startIndex;
1182 } else if (is_lwsp (this.c_str[i])) {
1183 return i - startIndex;
1190 public string[] Split (params char[] separator)
1194 * @separator: delimiting chars or null to split on whtspc
1196 * Returns: 1. An array consisting of a single
1197 * element (@this) if none of the delimiting
1198 * chars appear in @this. 2. An array of
1199 * substrings which are delimited by one of
1200 * the separator chars. 3. An array of
1201 * substrings separated by whitespace if
1202 * @separator is null. The Empty string should
1203 * be returned wherever 2 delimiting chars are
1206 // FIXME: would using a Queue be better?
1211 list = new ArrayList ();
1212 for (index = 0, len = 0; index < this.length; index += len + 1) {
1213 len = splitme (separator, index);
1214 len = len > -1 ? len : this.length - index;
1216 list.Add (String.Empty);
1221 str = new char [len + 1];
1222 for (i = 0; i < len; i++)
1223 str[i] = this.c_str[index + i];
1226 list.Add (new String (str));
1230 strings = new string [list.Count];
1231 if (list.Count == 1) {
1232 /* special case for an array holding @this */
1235 for (index = 0; index < list.Count; index++)
1236 strings[index] = (string) list[index];
1242 public string[] Split (char[] separator, int maxCount)
1244 // FIXME: what to do if maxCount <= 0?
1245 // FIXME: would using Queue be better than ArrayList?
1248 int index, len, used;
1251 list = new ArrayList ();
1252 for (index = 0, len = 0; index < this.length && used < maxCount; index += len + 1) {
1253 len = splitme (separator, index);
1254 len = len > -1 ? len : this.length - index;
1256 list.Add (String.Empty);
1261 str = new char [len + 1];
1262 for (i = 0; i < len; i++)
1263 str[i] = this.c_str[index + i];
1266 list.Add (new String (str));
1271 /* fit the remaining chunk of the @this into it's own element */
1272 if (index != this.length) {
1276 str = new char [this.length - index + 1];
1277 for (i = index; i < this.length; i++)
1278 str[i - index] = this.c_str[i];
1279 str[i - index] = '\0';
1281 list.Add (new String (str));
1284 strings = new string [list.Count];
1285 if (list.Count == 1) {
1286 /* special case for an array holding @this */
1289 for (index = 0; index < list.Count; index++)
1290 strings[index] = (string) list[index];
1296 public bool StartsWith (string value)
1298 bool startswith = true;
1302 throw new ArgumentNullException ();
1304 if (value.Length > this.length)
1307 for (i = 0; i < value.Length && startswith; i++)
1308 startswith = startswith && value[i] == this.c_str[i];
1313 public string Substring (int startIndex)
1318 if (startIndex < 0 || startIndex > this.length)
1319 throw new ArgumentOutOfRangeException ();
1321 len = this.length - startIndex;
1323 return String.Empty;
1325 str = new char [len + 1];
1326 for (i = startIndex; i < this.length; i++)
1327 str[i - startIndex] = this.c_str[i];
1330 return new String (str);
1333 public string Substring (int startIndex, int length)
1338 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1339 throw new ArgumentOutOfRangeException ();
1342 return String.Empty;
1344 str = new char [length + 1];
1345 for (i = startIndex; i < startIndex + length; i++)
1346 str[i - startIndex] = this.c_str[i];
1349 return new String (str);
1352 public bool ToBoolean (IFormatProvider provider)
1354 // FIXME: implement me
1358 public byte ToByte (IFormatProvider provider)
1360 // FIXME: implement me
1364 public char ToChar (IFormatProvider provider)
1366 // FIXME: implement me
1370 public char[] ToCharArray ()
1372 return ToCharArray (0, this.length);
1375 public char[] ToCharArray (int startIndex, int length)
1380 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1381 throw new ArgumentOutOfRangeException ();
1383 chars = new char [length + 1];
1384 for (i = startIndex; i < length; i++)
1385 chars[i - startIndex] = this.c_str[i];
1387 chars[length] = '\0';
1392 public DateTime ToDateTime (IFormatProvider provider)
1394 // FIXME: implement me
1396 return new DateTime (0);
1399 public decimal ToDecimal (IFormatProvider provider)
1401 // FIXME: implement me
1405 public double ToDouble (IFormatProvider provider)
1407 // FIXME: implement me
1411 public short ToInt16 (IFormatProvider provider)
1413 // FIXME: implement me
1417 public int ToInt32 (IFormatProvider provider)
1419 // FIXME: implement me
1423 public long ToInt64 (IFormatProvider provider)
1425 // FIXME: implement me
1429 public string ToLower ()
1434 str = new char [this.length + 1];
1435 for (i = 0; i < this.length; i++)
1436 str[i] = Char.ToLower (this.c_str[i]);
1439 return new String (str);
1442 public string ToLower (CultureInfo culture)
1444 // FIXME: implement me
1448 public sbyte ToSByte (IFormatProvider provider)
1450 // FIXME: implement me
1454 public float ToSingle (IFormatProvider provider)
1456 // FIXME: implement me
1460 public override string ToString ()
1462 return Substring (0, this.length);
1465 public string ToString (IFormatProvider format)
1467 // FIXME: implement me
1471 public object ToType (Type conversionType, IFormatProvider provider)
1473 // FIXME: implement me
1477 public ushort ToUInt16 (IFormatProvider provider)
1479 // FIXME: implement me
1483 public uint ToUInt32 (IFormatProvider provider)
1485 // FIXME: implement me
1489 public ulong ToUInt64 (IFormatProvider provider)
1491 // FIXME: implement me
1495 public string ToUpper ()
1500 str = new char [this.length + 1];
1501 for (i = 0; i < this.length; i++)
1502 str[i] = Char.ToUpper (this.c_str[i]);
1505 return new String (str);
1508 public string ToUpper (CultureInfo culture)
1510 // FIXME: implement me
1514 public string Trim ()
1519 public string Trim (params char[] trimChars)
1525 for (begin = 0; matches && begin < this.length; begin++) {
1526 if (trimChars != null) {
1528 foreach (char c in trimChars) {
1529 matches = this.c_str[begin] == c;
1534 matches = is_lwsp (this.c_str[begin]);
1539 for (end = this.length; end > begin; end--) {
1540 if (trimChars != null) {
1542 foreach (char c in trimChars) {
1543 matches = this.c_str[end] == c;
1548 matches = is_lwsp (this.c_str[end]);
1553 return String.Empty;
1555 return Substring (begin, end - begin);
1558 public string TrimEnd (params char[] trimChars)
1560 bool matches = true;
1563 for (end = this.length; end > 0; end--) {
1564 if (trimChars != null) {
1566 foreach (char c in trimChars) {
1567 matches = this.c_str[end] == c;
1572 matches = is_lwsp (this.c_str[end]);
1577 return String.Empty;
1579 return Substring (0, end);
1582 public string TrimStart (params char[] trimChars)
1584 bool matches = true;
1587 for (begin = 0; matches && begin < this.length; begin++) {
1588 if (trimChars != null) {
1590 foreach (char c in trimChars) {
1591 matches = this.c_str[begin] == c;
1596 matches = is_lwsp (this.c_str[begin]);
1600 if (begin == this.length)
1601 return String.Empty;
1603 return Substring (begin, this.length - begin);
1607 public static bool operator ==(string a, string b)
1609 if (a.length != b.length)
1613 for (int i = 0; i < l; i++)
1614 if (a.c_str [i] != b.c_str [i])
1620 public static bool operator !=(string a, string b)