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 internal String (int storage)
42 c_str = new char [storage];
46 unsafe public String (char *value)
50 // FIXME: can I do value.Length here?
54 for (i = 0; *(value + i) != '\0'; i++);
58 this.c_str = new char [this.length + 1];
59 for (i = 0; i < this.length; i++)
60 this.c_str[i] = *(value + i);
63 public String (char[] value)
67 // FIXME: value.Length includes the terminating null char?
68 this.length = value != null ? strlen (value): 0;
69 this.c_str = new char [this.length + 1];
70 for (i = 0; i < this.length; i++)
71 this.c_str[i] = value[i];
75 unsafe public String (sbyte *value)
77 // FIXME: consider unicode?
80 // FIXME: can I do value.Length here? */
84 for (i = 0; *(value + i) != '\0'; i++);
88 this.c_str = new char [this.length + 1];
89 for (i = 0; i < this.length; i++)
90 this.c_str[i] = (char) *(value + i);
93 public String (char c, int count)
98 this.c_str = new char [count + 1];
99 for (i = 0; i < count; i++)
103 [CLSCompliant(false)]
104 unsafe public String (char *value, int startIndex, int length)
108 if (value == null && startIndex != 0 && length != 0)
109 throw new ArgumentNullException ();
111 if (startIndex < 0 || length < 0)
112 throw new ArgumentOutOfRangeException ();
114 this.length = length;
115 this.c_str = new char [length + 1];
116 for (i = 0; i < length; i++)
117 this.c_str[i] = *(value + startIndex + i);
120 public String (char[] value, int startIndex, int length)
124 if (value == null && startIndex != 0 && length != 0)
125 throw new ArgumentNullException ();
127 if (startIndex < 0 || length < 0)
128 throw new ArgumentOutOfRangeException ();
130 this.length = length;
131 this.c_str = new char [length + 1];
132 for (i = 0; i < length; i++)
133 this.c_str[i] = value[startIndex + i];
136 [CLSCompliant(false)]
137 unsafe public String (sbyte *value, int startIndex, int length)
139 // FIXME: consider unicode?
142 if (value == null && startIndex != 0 && length != 0)
143 throw new ArgumentNullException ();
145 if (startIndex < 0 || length < 0)
146 throw new ArgumentOutOfRangeException ();
148 this.length = length;
149 this.c_str = new char [length + 1];
150 for (i = 0; i < length; i++)
151 this.c_str[i] = (char) *(value + startIndex + i);
154 [CLSCompliant(false)][MonoTODO]
155 unsafe public String (sbyte *value, int startIndex, int length, Encoding enc)
157 // FIXME: implement me
162 // FIXME: is there anything we need to do here?
163 /*base.Finalize ();*/
173 // FIXME: is this correct syntax??
174 public char this [int index] {
176 if (index >= this.length)
177 throw new ArgumentOutOfRangeException ();
179 return this.c_str[index];
183 // Private helper methods
184 private static int strlen (char[] str)
186 // FIXME: if str.Length includes terminating null char, then return (str.Length - 1)
191 private static char tolowerordinal (char c)
193 // FIXME: implement me
197 private static bool is_lwsp (char c)
199 /* this comes from the msdn docs for String.Trim() */
200 if ((c >= '\x9' && c <= '\xD') || c == '\x20' || c == '\xA0' ||
201 (c >= '\x2000' && c <= '\x200B') || c == '\x3000' || c == '\xFEFF')
207 private static int BoyerMoore (char[] haystack, string needle, int startIndex, int count)
209 /* (hopefully) Unicode-safe Boyer-Moore implementation */
210 int[] skiptable = new int[65536]; /* our unicode-safe skip-table */
211 int h, n, he, ne, hc, nc, i;
213 if (haystack == null || needle == null)
214 throw new ArgumentNullException ();
216 /* if the search buffer is shorter than the pattern buffer, we can't match */
217 if (count < needle.Length)
220 /* return an instant match if the pattern is 0-length */
221 if (needle.Length == 0)
224 /* set a pointer at the end of each string */
225 ne = needle.Length - 1; /* position of char before '\0' */
226 he = startIndex + count; /* position of last valid char */
228 /* init the skip table with the pattern length */
229 for (i = 0; i < 65536; i++)
230 skiptable[i] = needle.Length;
232 /* set the skip value for the chars that *do* appear in the
233 * pattern buffer (needle) to the distance from the index to
234 * the end of the pattern buffer. */
235 for (nc = 0; nc < ne; nc++)
236 skiptable[(int) needle[nc]] = ne - nc;
239 while (count >= needle.Length) {
240 hc = h + needle.Length - 1; /* set the haystack compare pointer */
241 nc = ne; /* set the needle compare pointer */
243 /* work our way backwards until they don't match */
244 for (i = 0; nc > 0; nc--, hc--, i++)
245 if (needle[nc] != haystack[hc])
248 if (needle[nc] != haystack[hc]) {
249 n = skiptable[(int) haystack[hc]] - i;
261 public object Clone ()
263 // FIXME: implement me
267 public static int Compare (string strA, string strB)
276 } else if (strB == null)
279 min = strA.length < strB.length ? strA.length : strB.length;
281 for (i = 0; i < min; i++) {
282 if (strA.c_str[i] != strB.c_str[i]) {
283 return (int)strA.c_str[i] - (int)strB.c_str[i];
286 if (strA.length == strB.length) {
289 if (strA.length > min) {
296 public static int Compare (string strA, string strB, bool ignoreCase)
301 return Compare (strA, strB);
304 * And here I thought Eazel developers were on crack...
305 * if a string is null it should pelt the programmer with
306 * ArgumentNullExceptions, damnit!
313 } else if (strB == null)
316 min = strA.length < strB.length ? strA.length : strB.length;
318 for (i = 0; i < min; i++) {
319 if (Char.ToLower (strA.c_str[i]) != Char.ToLower (strB.c_str[i]))
323 return ((int) (strA.c_str[i] - strB.c_str[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 (Char.ToLower (strA[indexA + i]) != Char.ToLower (strB[indexB + i]))
388 return ((int) (strA[indexA + i] - strB[indexB + i]));
392 public static int Compare (string strA, int indexA, string strB, int indexB,
393 int length, bool ignoreCase, CultureInfo culture)
396 throw new ArgumentNullException ();
398 if (length < 0 || indexA < 0 || indexB < 0)
399 throw new ArgumentOutOfRangeException ();
401 if (indexA > strA.Length || indexB > strB.Length)
402 throw new ArgumentOutOfRangeException ();
404 /* I can't take it anymore! */
410 } else if (strB == null)
413 // FIXME: implement me
417 public static int CompareOrdinal (string strA, string strB)
421 /* Please God, make it stop! */
427 } else if (strB == null)
430 for (i = 0; i < strA.Length && i < strB.Length; i++) {
433 cA = tolowerordinal (strA[i]);
434 cB = tolowerordinal (strB[i]);
440 return ((int) (strA[i] - strB[i]));
443 public static int CompareOrdinal (string strA, int indexA, string strB, int indexB,
448 if (length < 0 || indexA < 0 || indexB < 0)
449 throw new ArgumentOutOfRangeException ();
456 } else if (strB == null)
459 for (i = 0; i < length; i++) {
462 cA = tolowerordinal (strA[indexA + i]);
463 cB = tolowerordinal (strB[indexB + i]);
469 return ((int) (strA[indexA + i] - strB[indexB + i]));
472 public int CompareTo (object obj)
474 return Compare (this, obj == null ? null : obj.ToString ());
477 public int CompareTo (string str)
479 return Compare (this, str);
482 public static string Concat (object arg)
484 return arg != null ? arg.ToString () : String.Empty;
487 public static string Concat (params object[] args)
494 throw new ArgumentNullException ();
496 strings = new string [args.Length];
499 foreach (object arg in args) {
500 /* use Empty for each null argument */
502 strings[i] = String.Empty;
504 strings[i] = arg.ToString ();
505 len += strings[i].length;
512 String res = new String (len);
515 for (int j = 0; j < strings.Length; j++)
516 for (int k = 0; k < strings[j].length; k++)
517 str[i++] = strings[j].c_str[k];
522 public static string Concat (params string[] values)
528 throw new ArgumentNullException ();
531 foreach (string value in values)
532 len += value != null ? value.Length : 0;
537 String res = new String (len);
540 foreach (string value in values) {
544 for (int j = 0; j < value.length; j++)
545 str[i++] = value.c_str[j];
551 public static string Concat (object arg0, object arg1)
553 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
554 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
556 return Concat (str0, str1);
559 public static string Concat (string str0, string str1)
569 len = str0.length + str1.length;
573 String res = new String (len);
576 for (i = 0; i < str0.length; i++)
577 concat[i] = str0.c_str[i];
578 for (j = 0 ; j < str1.length; j++)
579 concat[i + j] = str1.c_str[j];
584 public static string Concat (object arg0, object arg1, object arg2)
586 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
587 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
588 string str2 = arg2 != null ? arg2.ToString () : String.Empty;
590 return Concat (str0, str1, str2);
593 public static string Concat (string str0, string str1, string str2)
605 len = str0.length + str1.length + str2.length;
609 String res = new String (len);
612 for (i = 0; i < str0.length; i++)
613 concat[i] = str0.c_str[i];
614 for (j = 0; j < str1.length; j++)
615 concat[i + j] = str1.c_str[j];
616 for (k = 0; k < str2.length; k++)
617 concat[i + j + k] = str2.c_str[k];
622 public static string Concat (string str0, string str1, string str2, string str3)
636 len = str0.length + str1.length + str2.length + str3.length;
639 String res = new String (len);
642 for (i = 0; i < str0.length; i++)
643 concat[i] = str0.c_str[i];
644 for (j = 0; j < str1.length; j++)
645 concat[i + j] = str1.c_str[j];
646 for (k = 0; k < str2.length; k++)
647 concat[i + j + k] = str2.c_str[k];
648 for (l = 0; l < str3.length; l++)
649 concat[i + j + k + l] = str3.c_str[l];
654 public static string Copy (string str)
656 // FIXME: how do I *copy* a string if I can only have 1 of each?
658 throw new ArgumentNullException ();
663 public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
665 // LAMESPEC: should I null-terminate?
668 if (destination == null)
669 throw new ArgumentNullException ();
671 if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
672 throw new ArgumentOutOfRangeException ();
674 if (sourceIndex + count > this.length)
675 throw new ArgumentOutOfRangeException ();
677 if (destinationIndex + count > destination.Length)
678 throw new ArgumentOutOfRangeException ();
680 for (i = 0; i < count; i++)
681 destination[destinationIndex + i] = this.c_str[sourceIndex + i];
684 public bool EndsWith (string value)
686 bool endswith = true;
690 throw new ArgumentNullException ();
692 start = this.length - value.length;
696 for (i = start; i < this.length && endswith; i++)
697 endswith = this.c_str[i] == value.c_str[i - start];
702 public override bool Equals (object obj)
704 if (!(obj is String))
707 return this == (String) obj;
710 public bool Equals (string value)
712 return this == value;
715 public static bool Equals (string a, string b)
721 public static string Format (string format, object arg0)
723 // FIXME: implement me
724 return format+arg0.ToString();
728 public static string Format (string format, params object[] args)
730 // FIXME: implement me
731 Console.WriteLine (args[0].ToString());
732 if (args.Length == 1)
733 return format+args[0].ToString();
734 if (args.Length == 2)
735 return format+args[0].ToString()+args[1].ToString();
736 if (args.Length == 3)
737 return format+args[0].ToString()+args[1].ToString()+args[2].ToString();
738 if (args.Length == 4)
739 return format+args[0].ToString()+args[1].ToString()+args[2].ToString()+args[3].ToString();
740 Console.WriteLine ("String.Format with args: "+args.Length.ToString());
745 public static string Format (IFormatProvider provider, string format, params object[] args)
747 // FIXME: implement me
752 public static string Format (string format, object arg0, object arg1)
754 // FIXME: implement me
755 return format+arg0.ToString()+arg1.ToString();
759 public static string Format (string format, object arg0, object arg1, object arg2)
761 // FIXME: implement me
762 return format+arg0.ToString()+arg1.ToString()+arg2.ToString();
765 //public CharEnumerator GetEnumerator ()
767 public IEnumerator GetEnumerator ()
769 // FIXME: implement me
773 public override int GetHashCode ()
777 for (i = 0; i < length; ++i)
778 h = (h << 5) - h + c_str [i];
782 public TypeCode GetTypeCode ()
784 return TypeCode.String;
787 public int IndexOf (char value)
789 return IndexOf (value, 0, this.length);
792 public int IndexOf (string value)
794 return IndexOf (value, 0, this.length);
797 public int IndexOf (char value, int startIndex)
799 return IndexOf (value, startIndex, this.length - startIndex);
802 public int IndexOf (string value, int startIndex)
804 return IndexOf (value, startIndex, this.length - startIndex);
807 public int IndexOf (char value, int startIndex, int count)
811 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
812 throw new ArgumentOutOfRangeException ();
814 for (i = startIndex; i - startIndex < count; i++)
815 if (this.c_str[i] == value)
821 public int IndexOf (string value, int startIndex, int count)
824 throw new ArgumentNullException ();
826 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
827 throw new ArgumentOutOfRangeException ();
829 return BoyerMoore (this.c_str, value, startIndex, count);
832 for (i = startIndex; i - startIndex + value.Length <= count; ) {
833 if (this.c_str[i] == value[0]) {
837 for (j = 1; equal && j < value.Length; j++) {
838 equal = this.c_str[i + j] == value[j];
839 if (this.c_str[i + j] == value[0] && nexti == 0)
858 public int IndexOfAny (char[] values)
860 return IndexOfAny (values, 0, this.length);
863 public int IndexOfAny (char[] values, int startIndex)
865 return IndexOfAny (values, startIndex, this.length - startIndex);
868 public int IndexOfAny (char[] values, int startIndex, int count)
871 throw new ArgumentNullException ();
873 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
874 throw new ArgumentOutOfRangeException ();
876 for (int i = startIndex; i < startIndex + count; i++) {
877 for (int j = 0; j < strlen (values); j++) {
878 if (this.c_str[i] == values[j])
886 public string Insert (int startIndex, string value)
892 throw new ArgumentNullException ();
894 if (startIndex < 0 || startIndex > this.length)
895 throw new ArgumentOutOfRangeException ();
897 String res = new String (value.length + this.length);
900 for (i = 0; i < startIndex; i++)
901 str[i] = this.c_str[i];
902 for (j = 0; j < value.length; j++)
903 str[i + j] = value.c_str[j];
904 for ( ; i < this.length; i++)
905 str[i + j] = this.c_str[i];
910 [MethodImplAttribute(MethodImplOptions.InternalCall)]
911 public extern static string Intern (string str);
913 [MethodImplAttribute(MethodImplOptions.InternalCall)]
914 public extern static string IsInterned (string str);
916 public static string Join (string separator, string[] value)
918 return Join (separator, value, 0, value.Length);
921 public static string Join (string separator, string[] value, int startIndex, int count)
923 // LAMESPEC: msdn doesn't specify what happens when separator is null
927 if (separator == null || value == null)
928 throw new ArgumentNullException ();
930 if (startIndex + count > value.Length)
931 throw new ArgumentOutOfRangeException ();
934 for (i = startIndex, used = 0; used < count; i++, used++) {
936 len += separator.length;
938 len += value[i].length;
941 // We have no elements to join?
945 String res = new String (len);
948 for (i = 0; i < value[startIndex].length; i++)
949 str[i] = value[startIndex][i];
952 for (j = startIndex + 1; used < count; j++, used++) {
955 for (k = 0; k < separator.length; k++)
956 str[i++] = separator.c_str[k];
957 for (k = 0; k < value[j].length; k++)
958 str[i++] = value[j].c_str[k];
964 public int LastIndexOf (char value)
970 for (; i >= 0; i--) {
971 if (this.c_str[i] == value)
978 public int LastIndexOf (string value)
980 return LastIndexOf (value, this.length, this.length);
983 public int LastIndexOf (char value, int startIndex)
985 if (startIndex < 0 || startIndex > this.length)
986 throw new ArgumentOutOfRangeException ();
988 for (int i = startIndex; i >= 0; i--) {
989 if (this.c_str[i] == value)
996 public int LastIndexOf (string value, int startIndex)
998 return LastIndexOf (value, startIndex, this.length);
1001 public int LastIndexOf (char value, int startIndex, int count)
1003 if (startIndex < 0 || count < 0)
1004 throw new ArgumentOutOfRangeException ();
1006 if (startIndex > this.length || startIndex - count < 0)
1007 throw new ArgumentOutOfRangeException ();
1009 for (int i = startIndex; i >= startIndex - count; i--) {
1010 if (this.c_str[i] == value)
1017 public int LastIndexOf (string value, int startIndex, int count)
1019 // LAMESPEC: currently I'm using startIndex as the 0-position in the comparison,
1020 // but maybe it's the end-position in MS's implementation?
1021 // msdn is unclear on this point. I think this is correct though.
1025 throw new ArgumentNullException ();
1027 if (startIndex < 0 || startIndex > this.length)
1028 throw new ArgumentOutOfRangeException ();
1030 if (count < 0 || startIndex - count < 0)
1031 throw new ArgumentOutOfRangeException ();
1033 if (value == String.Empty)
1036 if (startIndex + value.length > this.length) {
1037 /* just a little optimization */
1040 start = this.length - value.length;
1041 count -= startIndex - start;
1045 // FIXME: use a reversed-unicode-safe-Boyer-Moore?
1046 len = value.length - 1;
1047 for (i = startIndex; i >= startIndex - count; i--) {
1048 if (this.c_str[i + len] == value.c_str[len]) {
1052 for (j = len - 1; equal && j >= 0; j--)
1053 equal = this.c_str[i + j] == value.c_str[j];
1063 public int LastIndexOfAny (char[] values)
1065 return LastIndexOfAny (values, this.length, this.length);
1068 public int LastIndexOfAny (char[] values, int startIndex)
1070 return LastIndexOfAny (values, startIndex, startIndex);
1073 public int LastIndexOfAny (char[] values, int startIndex, int count)
1078 throw new ArgumentNullException ();
1080 if (startIndex < 0 || count < 0 || startIndex - count < 0)
1081 throw new ArgumentOutOfRangeException ();
1083 for (i = startIndex; i >= startIndex - count; i--) {
1084 for (int j = 0; j < strlen (values); j++) {
1085 if (this.c_str[i] == values[j])
1093 public string PadLeft (int totalWidth)
1095 return PadLeft (totalWidth, ' ');
1098 public string PadLeft (int totalWidth, char padChar)
1104 throw new ArgumentException ();
1106 str = new char [totalWidth > this.length ? totalWidth : this.length];
1107 for (i = 0; i < totalWidth - this.length; i++)
1110 for (j = 0; j < this.length; i++, j++)
1111 str[i] = this.c_str[j];
1113 return new String (str);
1116 public string PadRight (int totalWidth)
1118 return PadRight (totalWidth, ' ');
1121 public string PadRight (int totalWidth, char padChar)
1127 throw new ArgumentException ();
1129 str = new char [totalWidth > this.length ? totalWidth : this.length];
1130 for (i = 0; i < this.length; i++)
1131 str[i] = this.c_str[i];
1133 for ( ; i < str.Length; i++)
1136 return new String (str);
1139 public string Remove (int startIndex, int count)
1144 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
1145 throw new ArgumentOutOfRangeException ();
1147 len = this.length - count;
1149 return String.Empty;
1151 String res = new String (len);
1153 for (i = 0; i < startIndex; i++)
1154 str[i] = this.c_str[i];
1155 for (j = i + count; j < this.length; j++)
1156 str[i++] = this.c_str[j];
1161 public string Replace (char oldChar, char newChar)
1166 String res = new String (length);
1168 for (i = 0; i < this.length; i++) {
1169 if (this.c_str[i] == oldChar)
1172 str[i] = this.c_str[i];
1178 public string Replace (string oldValue, string newValue)
1180 // LAMESPEC: msdn doesn't specify what to do if either args is null
1181 int index, len, i, j;
1184 if (oldValue == null || newValue == null)
1185 throw new ArgumentNullException ();
1187 // Use IndexOf in case I later rewrite it to use Boyer-Moore
1188 index = IndexOf (oldValue, 0);
1190 // This is the easy one ;-)
1191 return Substring (0, this.length);
1194 len = this.length - oldValue.length + newValue.length;
1196 return String.Empty;
1198 String res = new String (len);
1200 for (i = 0; i < index; i++)
1201 str[i] = this.c_str[i];
1202 for (j = 0; j < newValue.length; j++)
1203 str[i++] = newValue[j];
1204 for (j = index + oldValue.length; j < this.length; j++)
1205 str[i++] = this.c_str[j];
1210 private int splitme (char[] separators, int startIndex)
1212 /* this is basically a customized IndexOfAny() for the Split() methods */
1213 for (int i = startIndex; i < this.length; i++) {
1214 if (separators != null) {
1215 foreach (char sep in separators) {
1216 if (this.c_str[i] == sep)
1217 return i - startIndex;
1219 } else if (is_lwsp (this.c_str[i])) {
1220 return i - startIndex;
1227 public string[] Split (params char[] separator)
1231 * @separator: delimiting chars or null to split on whtspc
1233 * Returns: 1. An array consisting of a single
1234 * element (@this) if none of the delimiting
1235 * chars appear in @this. 2. An array of
1236 * substrings which are delimited by one of
1237 * the separator chars. 3. An array of
1238 * substrings separated by whitespace if
1239 * @separator is null. The Empty string should
1240 * be returned wherever 2 delimiting chars are
1243 // FIXME: would using a Queue be better?
1248 list = new ArrayList ();
1249 for (index = 0, len = 0; index < this.length; index += len + 1) {
1250 len = splitme (separator, index);
1251 len = len > -1 ? len : this.length - index;
1253 list.Add (String.Empty);
1258 str = new char [len];
1259 for (i = 0; i < len; i++)
1260 str[i] = this.c_str[index + i];
1262 list.Add (new String (str));
1266 strings = new string [list.Count];
1267 if (list.Count == 1) {
1268 /* special case for an array holding @this */
1271 for (index = 0; index < list.Count; index++)
1272 strings[index] = (string) list[index];
1278 public string[] Split (char[] separator, int maxCount)
1280 // FIXME: what to do if maxCount <= 0?
1281 // FIXME: would using Queue be better than ArrayList?
1284 int index, len, used;
1287 list = new ArrayList ();
1288 for (index = 0, len = 0; index < this.length && used < maxCount; index += len + 1) {
1289 len = splitme (separator, index);
1290 len = len > -1 ? len : this.length - index;
1292 list.Add (String.Empty);
1297 str = new char [len];
1298 for (i = 0; i < len; i++)
1299 str[i] = this.c_str[index + i];
1301 list.Add (new String (str));
1306 /* fit the remaining chunk of the @this into it's own element */
1307 if (index != this.length) {
1311 str = new char [this.length - index];
1312 for (i = index; i < this.length; i++)
1313 str[i - index] = this.c_str[i];
1315 list.Add (new String (str));
1318 strings = new string [list.Count];
1319 if (list.Count == 1) {
1320 /* special case for an array holding @this */
1323 for (index = 0; index < list.Count; index++)
1324 strings[index] = (string) list[index];
1330 public bool StartsWith (string value)
1332 bool startswith = true;
1336 throw new ArgumentNullException ();
1338 if (value.length > this.length)
1341 for (i = 0; i < value.length && startswith; i++)
1342 startswith = startswith && value.c_str[i] == this.c_str[i];
1347 public string Substring (int startIndex)
1352 if (startIndex < 0 || startIndex > this.length)
1353 throw new ArgumentOutOfRangeException ();
1355 len = this.length - startIndex;
1357 return String.Empty;
1358 String res = new String (len);
1360 for (i = startIndex; i < this.length; i++)
1361 str[i - startIndex] = this.c_str[i];
1366 public string Substring (int startIndex, int length)
1371 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1372 throw new ArgumentOutOfRangeException ();
1375 return String.Empty;
1377 String res = new String (length);
1379 for (i = startIndex; i < startIndex + length; i++)
1380 str[i - startIndex] = this.c_str[i];
1386 public bool ToBoolean (IFormatProvider provider)
1388 // FIXME: implement me
1389 throw new NotImplementedException ();
1393 public byte ToByte (IFormatProvider provider)
1395 // FIXME: implement me
1396 throw new NotImplementedException ();
1400 public char ToChar (IFormatProvider provider)
1402 // FIXME: implement me
1403 throw new NotImplementedException ();
1406 public char[] ToCharArray ()
1408 return ToCharArray (0, this.length);
1411 public char[] ToCharArray (int startIndex, int length)
1416 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1417 throw new ArgumentOutOfRangeException ();
1419 chars = new char [length];
1420 for (i = startIndex; i < length; i++)
1421 chars[i - startIndex] = this.c_str[i];
1427 public DateTime ToDateTime (IFormatProvider provider)
1429 // FIXME: implement me
1430 // return new DateTime (0);
1431 throw new NotImplementedException ();
1435 public decimal ToDecimal (IFormatProvider provider)
1437 // FIXME: implement me
1438 throw new NotImplementedException ();
1442 public double ToDouble (IFormatProvider provider)
1444 // FIXME: implement me
1445 throw new NotImplementedException ();
1449 public short ToInt16 (IFormatProvider provider)
1451 // FIXME: implement me
1452 throw new NotImplementedException ();
1456 public int ToInt32 (IFormatProvider provider)
1458 // FIXME: implement me
1459 throw new NotImplementedException ();
1463 public long ToInt64 (IFormatProvider provider)
1465 // FIXME: implement me
1466 throw new NotImplementedException ();
1469 public string ToLower ()
1474 String res = new String (length);
1476 for (i = 0; i < this.length; i++)
1477 str[i] = Char.ToLower (this.c_str[i]);
1483 public string ToLower (CultureInfo culture)
1485 // FIXME: implement me
1486 throw new NotImplementedException ();
1490 [CLSCompliant(false)][MonoTODO]
1491 public sbyte ToSByte (IFormatProvider provider)
1493 // FIXME: implement me
1494 throw new NotImplementedException ();
1498 public float ToSingle (IFormatProvider provider)
1500 // FIXME: implement me
1501 throw new NotImplementedException ();
1504 public override string ToString ()
1510 public string ToString (IFormatProvider format)
1512 // FIXME: implement me
1513 throw new NotImplementedException ();
1517 public object ToType (Type conversionType, IFormatProvider provider)
1519 // FIXME: implement me
1520 throw new NotImplementedException ();
1523 [CLSCompliant(false)][MonoTODO]
1524 public ushort ToUInt16 (IFormatProvider provider)
1526 // FIXME: implement me
1527 throw new NotImplementedException ();
1530 [CLSCompliant(false)][MonoTODO]
1531 public uint ToUInt32 (IFormatProvider provider)
1533 // FIXME: implement me
1534 throw new NotImplementedException ();
1537 [CLSCompliant(false)][MonoTODO]
1538 public ulong ToUInt64 (IFormatProvider provider)
1540 // FIXME: implement me
1541 throw new NotImplementedException ();
1544 public string ToUpper ()
1549 String res = new String (length);
1551 for (i = 0; i < this.length; i++)
1552 str[i] = Char.ToUpper (this.c_str[i]);
1558 public string ToUpper (CultureInfo culture)
1560 // FIXME: implement me
1561 throw new NotImplementedException ();
1564 public string Trim ()
1569 public string Trim (params char[] trimChars)
1575 for (begin = 0; matches && begin < this.length; begin++) {
1576 if (trimChars != null) {
1578 foreach (char c in trimChars) {
1579 matches = this.c_str[begin] == c;
1584 matches = is_lwsp (this.c_str[begin]);
1589 for (end = this.length - 1; matches && end > begin; end--) {
1590 if (trimChars != null) {
1592 foreach (char c in trimChars) {
1593 matches = this.c_str[end] == c;
1598 matches = is_lwsp (this.c_str[end]);
1603 return String.Empty;
1605 return Substring (begin, end - begin);
1608 public string TrimEnd (params char[] trimChars)
1610 bool matches = true;
1613 for (end = this.length; end > 0; end--) {
1614 if (trimChars != null) {
1616 foreach (char c in trimChars) {
1617 matches = this.c_str[end] == c;
1622 matches = is_lwsp (this.c_str[end]);
1627 return String.Empty;
1629 return Substring (0, end);
1632 public string TrimStart (params char[] trimChars)
1634 bool matches = true;
1637 for (begin = 0; matches && begin < this.length; begin++) {
1638 if (trimChars != null) {
1640 foreach (char c in trimChars) {
1641 matches = this.c_str[begin] == c;
1646 matches = is_lwsp (this.c_str[begin]);
1650 if (begin == this.length)
1651 return String.Empty;
1653 return Substring (begin, this.length - begin);
1657 public static bool operator ==(string a, string b)
1659 if (a.length != b.length)
1663 for (int i = 0; i < l; i++)
1664 if (a.c_str[i] != b.c_str[i])
1670 public static bool operator !=(string a, string b)