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 */
230 for (i = 0; i < 65536; i++)
233 /* set the skip value for the chars that *do* appear in the
234 * pattern buffer (needle) to the distance from the index to
235 * the end of the pattern buffer. */
236 for (nc = 0; nc < ne; nc++)
237 skiptable[(int) needle[nc]] = ne - nc;
240 while (count >= needle.length) {
241 hc = h + needle.length - 1; /* set the haystack compare pointer */
242 nc = ne; /* set the needle compare pointer */
244 /* work our way backwards until they don't match */
245 for (i = 0; nc > 0; nc--, hc--, i++)
246 if (needle[nc] != haystack[hc])
249 if (needle[nc] != haystack[hc]) {
250 n = skiptable[(int) haystack[hc]] - i;
262 public object Clone ()
264 // FIXME: implement me
268 public static int Compare (string strA, string strB)
277 } else if (strB == null)
280 min = strA.length < strB.length ? strA.length : strB.length;
282 for (i = 0; i < min; i++) {
283 if (strA.c_str[i] != strB.c_str[i]) {
284 return (int)strA.c_str[i] - (int)strB.c_str[i];
287 if (strA.length == strB.length) {
290 if (strA.length > min) {
297 public static int Compare (string strA, string strB, bool ignoreCase)
302 return Compare (strA, strB);
305 * And here I thought Eazel developers were on crack...
306 * if a string is null it should pelt the programmer with
307 * ArgumentNullExceptions, damnit!
314 } else if (strB == null)
317 min = strA.length < strB.length ? strA.length : strB.length;
319 for (i = 0; i < min; i++) {
320 if (Char.ToLower (strA.c_str[i]) != Char.ToLower (strB.c_str[i]))
324 return ((int) (strA.c_str[i] - strB.c_str[i]));
328 public static int Compare (string strA, string strB, bool ignoreCase, CultureInfo culture)
330 // FIXME: implement me
334 public static int Compare (string strA, int indexA, string strB, int indexB, int length)
338 if (length < 0 || indexA < 0 || indexB < 0)
339 throw new ArgumentOutOfRangeException ();
341 if (indexA > strA.Length || indexB > strB.Length)
342 throw new ArgumentOutOfRangeException ();
344 /* And again with the ("" > null) logic... lord have mercy! */
350 } else if (strB == null)
353 for (i = 0; i < length - 1; i++) {
354 if (strA[indexA + i] != strB[indexB + i])
358 return ((int) (strA[indexA + i] - strB[indexB + i]));
361 public static int Compare (string strA, int indexA, string strB, int indexB,
362 int length, bool ignoreCase)
367 return Compare (strA, indexA, strB, indexB, length);
369 if (length < 0 || indexA < 0 || indexB < 0)
370 throw new ArgumentOutOfRangeException ();
372 if (indexA > strA.Length || indexB > strB.Length)
373 throw new ArgumentOutOfRangeException ();
375 /* When will the hurting stop!?!? */
381 } else if (strB == null)
384 for (i = 0; i < length - 1; i++) {
385 if (Char.ToLower (strA[indexA + i]) != Char.ToLower (strB[indexB + i]))
389 return ((int) (strA[indexA + i] - strB[indexB + i]));
393 public static int Compare (string strA, int indexA, string strB, int indexB,
394 int length, bool ignoreCase, CultureInfo culture)
397 throw new ArgumentNullException ();
399 if (length < 0 || indexA < 0 || indexB < 0)
400 throw new ArgumentOutOfRangeException ();
402 if (indexA > strA.Length || indexB > strB.Length)
403 throw new ArgumentOutOfRangeException ();
405 /* I can't take it anymore! */
411 } else if (strB == null)
414 // FIXME: implement me
418 public static int CompareOrdinal (string strA, string strB)
422 /* Please God, make it stop! */
428 } else if (strB == null)
431 for (i = 0; i < strA.Length && i < strB.Length; i++) {
434 cA = tolowerordinal (strA[i]);
435 cB = tolowerordinal (strB[i]);
441 return ((int) (strA[i] - strB[i]));
444 public static int CompareOrdinal (string strA, int indexA, string strB, int indexB,
449 if (length < 0 || indexA < 0 || indexB < 0)
450 throw new ArgumentOutOfRangeException ();
457 } else if (strB == null)
460 for (i = 0; i < length; i++) {
463 cA = tolowerordinal (strA[indexA + i]);
464 cB = tolowerordinal (strB[indexB + i]);
470 return ((int) (strA[indexA + i] - strB[indexB + i]));
473 public int CompareTo (object obj)
475 return Compare (this, obj == null ? null : obj.ToString ());
478 public int CompareTo (string str)
480 return Compare (this, str);
483 public static string Concat (object arg)
485 return arg != null ? arg.ToString () : String.Empty;
488 public static string Concat (params object[] args)
495 throw new ArgumentNullException ();
497 strings = new string [args.Length];
500 foreach (object arg in args) {
501 /* use Empty for each null argument */
503 strings[i] = String.Empty;
505 strings[i] = arg.ToString ();
506 len += strings[i].length;
513 String res = new String (len);
516 for (int j = 0; j < strings.Length; j++)
517 for (int k = 0; k < strings[j].length; k++)
518 str[i++] = strings[j].c_str[k];
523 public static string Concat (params string[] values)
529 throw new ArgumentNullException ();
532 foreach (string value in values)
533 len += value != null ? value.Length : 0;
538 String res = new String (len);
541 foreach (string value in values) {
545 for (int j = 0; j < value.length; j++)
546 str[i++] = value.c_str[j];
552 public static string Concat (object arg0, object arg1)
554 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
555 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
557 return Concat (str0, str1);
560 public static string Concat (string str0, string str1)
570 len = str0.length + str1.length;
574 String res = new String (len);
577 for (i = 0; i < str0.length; i++)
578 concat[i] = str0.c_str[i];
579 for (j = 0 ; j < str1.length; j++)
580 concat[i + j] = str1.c_str[j];
585 public static string Concat (object arg0, object arg1, object arg2)
587 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
588 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
589 string str2 = arg2 != null ? arg2.ToString () : String.Empty;
591 return Concat (str0, str1, str2);
594 public static string Concat (string str0, string str1, string str2)
606 len = str0.length + str1.length + str2.length;
610 String res = new String (len);
613 for (i = 0; i < str0.length; i++)
614 concat[i] = str0.c_str[i];
615 for (j = 0; j < str1.length; j++)
616 concat[i + j] = str1.c_str[j];
617 for (k = 0; k < str2.length; k++)
618 concat[i + j + k] = str2.c_str[k];
623 public static string Concat (string str0, string str1, string str2, string str3)
637 len = str0.length + str1.length + str2.length + str3.length;
640 String res = new String (len);
643 for (i = 0; i < str0.length; i++)
644 concat[i] = str0.c_str[i];
645 for (j = 0; j < str1.length; j++)
646 concat[i + j] = str1.c_str[j];
647 for (k = 0; k < str2.length; k++)
648 concat[i + j + k] = str2.c_str[k];
649 for (l = 0; l < str3.length; l++)
650 concat[i + j + k + l] = str3.c_str[l];
655 public static string Copy (string str)
657 // FIXME: how do I *copy* a string if I can only have 1 of each?
659 throw new ArgumentNullException ();
664 public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
666 // LAMESPEC: should I null-terminate?
669 if (destination == null)
670 throw new ArgumentNullException ();
672 if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
673 throw new ArgumentOutOfRangeException ();
675 if (sourceIndex + count > this.length)
676 throw new ArgumentOutOfRangeException ();
678 if (destinationIndex + count > destination.Length)
679 throw new ArgumentOutOfRangeException ();
681 for (i = 0; i < count; i++)
682 destination[destinationIndex + i] = this.c_str[sourceIndex + i];
685 public bool EndsWith (string value)
687 bool endswith = true;
691 throw new ArgumentNullException ();
693 start = this.length - value.length;
697 for (i = start; i < this.length && endswith; i++)
698 endswith = this.c_str[i] == value.c_str[i - start];
703 public override bool Equals (object obj)
705 if (!(obj is String))
708 return this == (String) obj;
711 public bool Equals (string value)
713 return this == value;
716 public static bool Equals (string a, string b)
722 public static string Format (string format, object arg0)
724 // FIXME: implement me
725 return format+arg0.ToString();
729 public static string Format (string format, params object[] args)
731 // FIXME: implement me
732 Console.WriteLine (args[0].ToString());
733 if (args.Length == 1)
734 return format+args[0].ToString();
735 if (args.Length == 2)
736 return format+args[0].ToString()+args[1].ToString();
737 if (args.Length == 3)
738 return format+args[0].ToString()+args[1].ToString()+args[2].ToString();
739 if (args.Length == 4)
740 return format+args[0].ToString()+args[1].ToString()+args[2].ToString()+args[3].ToString();
741 Console.WriteLine ("String.Format with args: "+args.Length.ToString());
746 public static string Format (IFormatProvider provider, string format, params object[] args)
748 // FIXME: implement me
753 public static string Format (string format, object arg0, object arg1)
755 // FIXME: implement me
756 return format+arg0.ToString()+arg1.ToString();
760 public static string Format (string format, object arg0, object arg1, object arg2)
762 // FIXME: implement me
763 return format+arg0.ToString()+arg1.ToString()+arg2.ToString();
766 //public CharEnumerator GetEnumerator ()
768 public IEnumerator GetEnumerator ()
770 // FIXME: implement me
774 public override int GetHashCode ()
778 for (i = 0; i < length; ++i)
779 h = (h << 5) - h + c_str [i];
783 public TypeCode GetTypeCode ()
785 return TypeCode.String;
788 public int IndexOf (char value)
790 return IndexOf (value, 0, this.length);
793 public int IndexOf (string value)
795 return IndexOf (value, 0, this.length);
798 public int IndexOf (char value, int startIndex)
800 return IndexOf (value, startIndex, this.length - startIndex);
803 public int IndexOf (string value, int startIndex)
805 return IndexOf (value, startIndex, this.length - startIndex);
808 public int IndexOf (char value, int startIndex, int count)
812 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
813 throw new ArgumentOutOfRangeException ();
815 for (i = startIndex; i - startIndex < count; i++)
816 if (this.c_str[i] == value)
822 public int IndexOf (string value, int startIndex, int count)
825 throw new ArgumentNullException ();
827 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
828 throw new ArgumentOutOfRangeException ();
830 return BoyerMoore (this.c_str, value, startIndex, count);
833 for (i = startIndex; i - startIndex + value.Length <= count; ) {
834 if (this.c_str[i] == value[0]) {
838 for (j = 1; equal && j < value.Length; j++) {
839 equal = this.c_str[i + j] == value[j];
840 if (this.c_str[i + j] == value[0] && nexti == 0)
859 public int IndexOfAny (char[] values)
861 return IndexOfAny (values, 0, this.length);
864 public int IndexOfAny (char[] values, int startIndex)
866 return IndexOfAny (values, startIndex, this.length - startIndex);
869 public int IndexOfAny (char[] values, int startIndex, int count)
872 throw new ArgumentNullException ();
874 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
875 throw new ArgumentOutOfRangeException ();
877 for (int i = startIndex; i < startIndex + count; i++) {
878 for (int j = 0; j < strlen (values); j++) {
879 if (this.c_str[i] == values[j])
887 public string Insert (int startIndex, string value)
893 throw new ArgumentNullException ();
895 if (startIndex < 0 || startIndex > this.length)
896 throw new ArgumentOutOfRangeException ();
898 String res = new String (value.length + this.length);
901 for (i = 0; i < startIndex; i++)
902 str[i] = this.c_str[i];
903 for (j = 0; j < value.length; j++)
904 str[i + j] = value.c_str[j];
905 for ( ; i < this.length; i++)
906 str[i + j] = this.c_str[i];
911 [MethodImplAttribute(MethodImplOptions.InternalCall)]
912 public extern static string Intern (string str);
914 [MethodImplAttribute(MethodImplOptions.InternalCall)]
915 public extern static string IsInterned (string str);
917 public static string Join (string separator, string[] value)
919 return Join (separator, value, 0, value.Length);
922 public static string Join (string separator, string[] value, int startIndex, int count)
924 // LAMESPEC: msdn doesn't specify what happens when separator is null
928 if (separator == null || value == null)
929 throw new ArgumentNullException ();
931 if (startIndex + count > value.Length)
932 throw new ArgumentOutOfRangeException ();
935 for (i = startIndex, used = 0; used < count; i++, used++) {
937 len += separator.length;
939 len += value[i].length;
942 // We have no elements to join?
946 String res = new String (len);
949 for (i = 0; i < value[startIndex].length; i++)
950 str[i] = value[startIndex][i];
953 for (j = startIndex + 1; used < count; j++, used++) {
956 for (k = 0; k < separator.length; k++)
957 str[i++] = separator.c_str[k];
958 for (k = 0; k < value[j].length; k++)
959 str[i++] = value[j].c_str[k];
965 public int LastIndexOf (char value)
971 for (; i >= 0; i--) {
972 if (this.c_str[i] == value)
979 public int LastIndexOf (string value)
981 return LastIndexOf (value, this.length - 1, this.length);
984 public int LastIndexOf (char value, int startIndex)
986 if (startIndex < 0 || startIndex >= this.length)
987 throw new ArgumentOutOfRangeException ();
989 for (int i = startIndex; i >= 0; i--) {
990 if (this.c_str[i] == value)
997 public int LastIndexOf (string value, int startIndex)
999 return LastIndexOf (value, startIndex, startIndex + 1);
1002 public int LastIndexOf (char value, int startIndex, int count)
1004 if (startIndex < 0 || count < 0)
1005 throw new ArgumentOutOfRangeException ();
1007 if (startIndex >= this.length || startIndex - count + 1 < 0)
1008 throw new ArgumentOutOfRangeException ();
1010 for (int i = startIndex; i > startIndex - count; i--) {
1011 if (this.c_str[i] == value)
1018 public int LastIndexOf (string value, int startIndex, int count)
1020 // LAMESPEC: currently I'm using startIndex as the 0-position in the comparison,
1021 // but maybe it's the end-position in MS's implementation?
1022 // msdn is unclear on this point. I think this is correct though.
1026 throw new ArgumentNullException ();
1028 if (startIndex < 0 || startIndex >= this.length)
1029 throw new ArgumentOutOfRangeException ();
1031 if (count < 0 || startIndex - count + 1 < 0)
1032 throw new ArgumentOutOfRangeException ();
1034 if (value == String.Empty)
1037 if (startIndex + value.length > this.length) {
1038 /* just a little optimization */
1041 start = this.length - value.length;
1042 count -= startIndex - start;
1046 // FIXME: use a reversed-unicode-safe-Boyer-Moore?
1047 len = value.length - 1;
1048 for (i = startIndex; i > startIndex - count; i--) {
1049 if (this.c_str[i + len] == value.c_str[len]) {
1053 for (j = len - 1; equal && j >= 0; j--)
1054 equal = this.c_str[i + j] == value.c_str[j];
1064 public int LastIndexOfAny (char[] values)
1066 return LastIndexOfAny (values, this.length - 1, this.length);
1069 public int LastIndexOfAny (char[] values, int startIndex)
1071 return LastIndexOfAny (values, startIndex, startIndex + 1);
1074 public int LastIndexOfAny (char[] values, int startIndex, int count)
1079 throw new ArgumentNullException ();
1081 if (startIndex < 0 || count < 0 || startIndex - count + 1 < 0)
1082 throw new ArgumentOutOfRangeException ();
1084 for (i = startIndex; i > startIndex - count; i--) {
1085 for (int j = 0; j < strlen (values); j++) {
1086 if (this.c_str[i] == values[j])
1094 public string PadLeft (int totalWidth)
1096 return PadLeft (totalWidth, ' ');
1099 public string PadLeft (int totalWidth, char padChar)
1105 throw new ArgumentException ();
1107 str = new char [totalWidth > this.length ? totalWidth : this.length];
1108 for (i = 0; i < totalWidth - this.length; i++)
1111 for (j = 0; j < this.length; i++, j++)
1112 str[i] = this.c_str[j];
1114 return new String (str);
1117 public string PadRight (int totalWidth)
1119 return PadRight (totalWidth, ' ');
1122 public string PadRight (int totalWidth, char padChar)
1128 throw new ArgumentException ();
1130 str = new char [totalWidth > this.length ? totalWidth : this.length];
1131 for (i = 0; i < this.length; i++)
1132 str[i] = this.c_str[i];
1134 for ( ; i < str.Length; i++)
1137 return new String (str);
1140 public string Remove (int startIndex, int count)
1145 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
1146 throw new ArgumentOutOfRangeException ();
1148 len = this.length - count;
1150 return String.Empty;
1152 String res = new String (len);
1154 for (i = 0; i < startIndex; i++)
1155 str[i] = this.c_str[i];
1156 for (j = i + count; j < this.length; j++)
1157 str[i++] = this.c_str[j];
1162 public string Replace (char oldChar, char newChar)
1167 String res = new String (length);
1169 for (i = 0; i < this.length; i++) {
1170 if (this.c_str[i] == oldChar)
1173 str[i] = this.c_str[i];
1179 public string Replace (string oldValue, string newValue)
1181 // LAMESPEC: msdn doesn't specify what to do if either args is null
1182 int index, len, i, j;
1185 if (oldValue == null || newValue == null)
1186 throw new ArgumentNullException ();
1188 // Use IndexOf in case I later rewrite it to use Boyer-Moore
1189 index = IndexOf (oldValue, 0);
1191 // This is the easy one ;-)
1192 return Substring (0, this.length);
1195 len = this.length - oldValue.length + newValue.length;
1197 return String.Empty;
1199 String res = new String (len);
1201 for (i = 0; i < index; i++)
1202 str[i] = this.c_str[i];
1203 for (j = 0; j < newValue.length; j++)
1204 str[i++] = newValue[j];
1205 for (j = index + oldValue.length; j < this.length; j++)
1206 str[i++] = this.c_str[j];
1211 private int splitme (char[] separators, int startIndex)
1213 /* this is basically a customized IndexOfAny() for the Split() methods */
1214 for (int i = startIndex; i < this.length; i++) {
1215 if (separators != null) {
1216 foreach (char sep in separators) {
1217 if (this.c_str[i] == sep)
1218 return i - startIndex;
1220 } else if (is_lwsp (this.c_str[i])) {
1221 return i - startIndex;
1228 public string[] Split (params char[] separator)
1232 * @separator: delimiting chars or null to split on whtspc
1234 * Returns: 1. An array consisting of a single
1235 * element (@this) if none of the delimiting
1236 * chars appear in @this. 2. An array of
1237 * substrings which are delimited by one of
1238 * the separator chars. 3. An array of
1239 * substrings separated by whitespace if
1240 * @separator is null. The Empty string should
1241 * be returned wherever 2 delimiting chars are
1244 // FIXME: would using a Queue be better?
1249 list = new ArrayList ();
1250 for (index = 0, len = 0; index < this.length; index += len + 1) {
1251 len = splitme (separator, index);
1252 len = len > -1 ? len : this.length - index;
1254 list.Add (String.Empty);
1259 str = new char [len];
1260 for (i = 0; i < len; i++)
1261 str[i] = this.c_str[index + i];
1263 list.Add (new String (str));
1267 strings = new string [list.Count];
1268 if (list.Count == 1) {
1269 /* special case for an array holding @this */
1272 for (index = 0; index < list.Count; index++)
1273 strings[index] = (string) list[index];
1279 public string[] Split (char[] separator, int maxCount)
1281 // FIXME: what to do if maxCount <= 0?
1282 // FIXME: would using Queue be better than ArrayList?
1285 int index, len, used;
1288 list = new ArrayList ();
1289 for (index = 0, len = 0; index < this.length && used < maxCount; index += len + 1) {
1290 len = splitme (separator, index);
1291 len = len > -1 ? len : this.length - index;
1293 list.Add (String.Empty);
1298 str = new char [len];
1299 for (i = 0; i < len; i++)
1300 str[i] = this.c_str[index + i];
1302 list.Add (new String (str));
1307 /* fit the remaining chunk of the @this into it's own element */
1308 if (index != this.length) {
1312 str = new char [this.length - index];
1313 for (i = index; i < this.length; i++)
1314 str[i - index] = this.c_str[i];
1316 list.Add (new String (str));
1319 strings = new string [list.Count];
1320 if (list.Count == 1) {
1321 /* special case for an array holding @this */
1324 for (index = 0; index < list.Count; index++)
1325 strings[index] = (string) list[index];
1331 public bool StartsWith (string value)
1333 bool startswith = true;
1337 throw new ArgumentNullException ();
1339 if (value.length > this.length)
1342 for (i = 0; i < value.length && startswith; i++)
1343 startswith = startswith && value.c_str[i] == this.c_str[i];
1348 public string Substring (int startIndex)
1353 if (startIndex < 0 || startIndex > this.length)
1354 throw new ArgumentOutOfRangeException ();
1356 len = this.length - startIndex;
1358 return String.Empty;
1359 String res = new String (len);
1361 for (i = startIndex; i < this.length; i++)
1362 str[i - startIndex] = this.c_str[i];
1367 public string Substring (int startIndex, int length)
1372 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1373 throw new ArgumentOutOfRangeException ();
1376 return String.Empty;
1378 String res = new String (length);
1380 for (i = startIndex; i < startIndex + length; i++)
1381 str[i - startIndex] = this.c_str[i];
1387 public bool ToBoolean (IFormatProvider provider)
1389 // FIXME: implement me
1390 throw new NotImplementedException ();
1394 public byte ToByte (IFormatProvider provider)
1396 // FIXME: implement me
1397 throw new NotImplementedException ();
1401 public char ToChar (IFormatProvider provider)
1403 // FIXME: implement me
1404 throw new NotImplementedException ();
1407 public char[] ToCharArray ()
1409 return ToCharArray (0, this.length);
1412 public char[] ToCharArray (int startIndex, int length)
1417 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1418 throw new ArgumentOutOfRangeException ();
1420 chars = new char [length];
1421 for (i = startIndex; i < length; i++)
1422 chars[i - startIndex] = this.c_str[i];
1428 public DateTime ToDateTime (IFormatProvider provider)
1430 // FIXME: implement me
1431 // return new DateTime (0);
1432 throw new NotImplementedException ();
1436 public decimal ToDecimal (IFormatProvider provider)
1438 // FIXME: implement me
1439 throw new NotImplementedException ();
1443 public double ToDouble (IFormatProvider provider)
1445 // FIXME: implement me
1446 throw new NotImplementedException ();
1450 public short ToInt16 (IFormatProvider provider)
1452 // FIXME: implement me
1453 throw new NotImplementedException ();
1457 public int ToInt32 (IFormatProvider provider)
1459 // FIXME: implement me
1460 throw new NotImplementedException ();
1464 public long ToInt64 (IFormatProvider provider)
1466 // FIXME: implement me
1467 throw new NotImplementedException ();
1470 public string ToLower ()
1475 String res = new String (length);
1477 for (i = 0; i < this.length; i++)
1478 str[i] = Char.ToLower (this.c_str[i]);
1484 public string ToLower (CultureInfo culture)
1486 // FIXME: implement me
1487 throw new NotImplementedException ();
1491 [CLSCompliant(false)][MonoTODO]
1492 public sbyte ToSByte (IFormatProvider provider)
1494 // FIXME: implement me
1495 throw new NotImplementedException ();
1499 public float ToSingle (IFormatProvider provider)
1501 // FIXME: implement me
1502 throw new NotImplementedException ();
1505 public override string ToString ()
1511 public string ToString (IFormatProvider format)
1513 // FIXME: implement me
1514 throw new NotImplementedException ();
1518 public object ToType (Type conversionType, IFormatProvider provider)
1520 // FIXME: implement me
1521 throw new NotImplementedException ();
1524 [CLSCompliant(false)][MonoTODO]
1525 public ushort ToUInt16 (IFormatProvider provider)
1527 // FIXME: implement me
1528 throw new NotImplementedException ();
1531 [CLSCompliant(false)][MonoTODO]
1532 public uint ToUInt32 (IFormatProvider provider)
1534 // FIXME: implement me
1535 throw new NotImplementedException ();
1538 [CLSCompliant(false)][MonoTODO]
1539 public ulong ToUInt64 (IFormatProvider provider)
1541 // FIXME: implement me
1542 throw new NotImplementedException ();
1545 public string ToUpper ()
1550 String res = new String (length);
1552 for (i = 0; i < this.length; i++)
1553 str[i] = Char.ToUpper (this.c_str[i]);
1559 public string ToUpper (CultureInfo culture)
1561 // FIXME: implement me
1562 throw new NotImplementedException ();
1565 public string Trim ()
1570 public string Trim (params char[] trimChars)
1576 for (begin = 0; matches && begin < this.length; begin++) {
1577 if (trimChars != null) {
1579 foreach (char c in trimChars) {
1580 matches = this.c_str[begin] == c;
1585 matches = is_lwsp (this.c_str[begin]);
1590 for (end = this.length - 1; matches && end > begin; end--) {
1591 if (trimChars != null) {
1593 foreach (char c in trimChars) {
1594 matches = this.c_str[end] == c;
1599 matches = is_lwsp (this.c_str[end]);
1604 return String.Empty;
1606 return Substring (begin, end - begin);
1609 public string TrimEnd (params char[] trimChars)
1611 bool matches = true;
1614 for (end = this.length; end > 0; end--) {
1615 if (trimChars != null) {
1617 foreach (char c in trimChars) {
1618 matches = this.c_str[end] == c;
1623 matches = is_lwsp (this.c_str[end]);
1628 return String.Empty;
1630 return Substring (0, end);
1633 public string TrimStart (params char[] trimChars)
1635 bool matches = true;
1638 for (begin = 0; matches && begin < this.length; begin++) {
1639 if (trimChars != null) {
1641 foreach (char c in trimChars) {
1642 matches = this.c_str[begin] == c;
1647 matches = is_lwsp (this.c_str[begin]);
1651 if (begin == this.length)
1652 return String.Empty;
1654 return Substring (begin, this.length - begin);
1658 public static bool operator ==(string a, string b)
1660 if ((object)a == null) {
1661 if ((object)b == null)
1665 if ((object)b == null)
1668 if (a.length != b.length)
1672 for (int i = 0; i < l; i++)
1673 if (a.c_str[i] != b.c_str[i])
1679 public static bool operator !=(string a, string b)