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 [DefaultMemberName("Chars")]
33 public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable {
34 public static readonly string Empty = "";
40 internal String (int storage)
43 c_str = new char [storage];
47 unsafe public String (char *value)
51 // FIXME: can I do value.Length here?
55 for (i = 0; *(value + i) != '\0'; i++);
59 this.c_str = new char [this.length + 1];
60 for (i = 0; i < this.length; i++)
61 this.c_str[i] = *(value + i);
64 public String (char[] value)
68 // FIXME: value.Length includes the terminating null char?
69 this.length = value != null ? strlen (value): 0;
70 this.c_str = new char [this.length + 1];
71 for (i = 0; i < this.length; i++)
72 this.c_str[i] = value[i];
76 unsafe public String (sbyte *value)
78 // FIXME: consider unicode?
81 // FIXME: can I do value.Length here? */
85 for (i = 0; *(value + i) != '\0'; i++);
89 this.c_str = new char [this.length + 1];
90 for (i = 0; i < this.length; i++)
91 this.c_str[i] = (char) *(value + i);
94 public String (char c, int count)
99 this.c_str = new char [count + 1];
100 for (i = 0; i < count; i++)
104 [CLSCompliant(false)]
105 unsafe public String (char *value, int startIndex, int length)
109 if (value == null && startIndex != 0 && length != 0)
110 throw new ArgumentNullException ();
112 if (startIndex < 0 || length < 0)
113 throw new ArgumentOutOfRangeException ();
115 this.length = length;
116 this.c_str = new char [length + 1];
117 for (i = 0; i < length; i++)
118 this.c_str[i] = *(value + startIndex + i);
121 public String (char[] value, int startIndex, int length)
125 if (value == null && startIndex != 0 && length != 0)
126 throw new ArgumentNullException ();
128 if (startIndex < 0 || length < 0)
129 throw new ArgumentOutOfRangeException ();
131 this.length = length;
132 this.c_str = new char [length + 1];
133 for (i = 0; i < length; i++)
134 this.c_str[i] = value[startIndex + i];
137 [CLSCompliant(false)]
138 unsafe public String (sbyte *value, int startIndex, int length)
140 // FIXME: consider unicode?
143 if (value == null && startIndex != 0 && length != 0)
144 throw new ArgumentNullException ();
146 if (startIndex < 0 || length < 0)
147 throw new ArgumentOutOfRangeException ();
149 this.length = length;
150 this.c_str = new char [length + 1];
151 for (i = 0; i < length; i++)
152 this.c_str[i] = (char) *(value + startIndex + i);
155 [CLSCompliant(false)][MonoTODO]
156 unsafe public String (sbyte *value, int startIndex, int length, Encoding enc)
158 // FIXME: implement me
163 // FIXME: is there anything we need to do here?
164 /*base.Finalize ();*/
174 [IndexerName("Chars")]
175 public char this [int index] {
177 if (index >= this.length)
178 throw new ArgumentOutOfRangeException ();
180 return this.c_str[index];
184 // Private helper methods
185 private static int strlen (char[] str)
187 // FIXME: if str.Length includes terminating null char, then return (str.Length - 1)
192 private static char tolowerordinal (char c)
194 // FIXME: implement me
198 private static bool is_lwsp (char c)
200 /* this comes from the msdn docs for String.Trim() */
201 if ((c >= '\x9' && c <= '\xD') || c == '\x20' || c == '\xA0' ||
202 (c >= '\x2000' && c <= '\x200B') || c == '\x3000' || c == '\xFEFF')
208 private static int BoyerMoore (char[] haystack, string needle, int startIndex, int count)
210 /* (hopefully) Unicode-safe Boyer-Moore implementation */
211 int[] skiptable = new int[65536]; /* our unicode-safe skip-table */
212 int h, n, he, ne, hc, nc, i;
214 if (haystack == null || needle == null)
215 throw new ArgumentNullException ();
217 /* if the search buffer is shorter than the pattern buffer, we can't match */
218 if (count < needle.length)
221 /* return an instant match if the pattern is 0-length */
222 if (needle.length == 0)
225 /* set a pointer at the end of each string */
226 ne = needle.length - 1; /* position of char before '\0' */
227 he = startIndex + count; /* position of last valid char */
229 /* init the skip table with the pattern length */
231 for (i = 0; i < 65536; i++)
234 /* set the skip value for the chars that *do* appear in the
235 * pattern buffer (needle) to the distance from the index to
236 * the end of the pattern buffer. */
237 for (nc = 0; nc < ne; nc++)
238 skiptable[(int) needle[nc]] = ne - nc;
241 while (count >= needle.length) {
242 hc = h + needle.length - 1; /* set the haystack compare pointer */
243 nc = ne; /* set the needle compare pointer */
245 /* work our way backwards until they don't match */
246 for (i = 0; nc > 0; nc--, hc--, i++)
247 if (needle[nc] != haystack[hc])
250 if (needle[nc] != haystack[hc]) {
251 n = skiptable[(int) haystack[hc]] - i;
263 public object Clone ()
265 // FIXME: implement me
269 public static int Compare (string strA, string strB)
278 } else if (strB == null)
281 min = strA.length < strB.length ? strA.length : strB.length;
283 for (i = 0; i < min; i++) {
284 if (strA.c_str[i] != strB.c_str[i]) {
285 return (int)strA.c_str[i] - (int)strB.c_str[i];
288 if (strA.length == strB.length) {
291 if (strA.length > min) {
298 public static int Compare (string strA, string strB, bool ignoreCase)
303 return Compare (strA, strB);
306 * And here I thought Eazel developers were on crack...
307 * if a string is null it should pelt the programmer with
308 * ArgumentNullExceptions, damnit!
315 } else if (strB == null)
318 min = strA.length < strB.length ? strA.length : strB.length;
320 for (i = 0; i < min; i++) {
321 if (Char.ToLower (strA.c_str[i]) != Char.ToLower (strB.c_str[i]))
325 return ((int) (strA.c_str[i] - strB.c_str[i]));
329 public static int Compare (string strA, string strB, bool ignoreCase, CultureInfo culture)
331 // FIXME: implement me
335 public static int Compare (string strA, int indexA, string strB, int indexB, int length)
339 if (length < 0 || indexA < 0 || indexB < 0)
340 throw new ArgumentOutOfRangeException ();
342 if (indexA > strA.Length || indexB > strB.Length)
343 throw new ArgumentOutOfRangeException ();
345 /* And again with the ("" > null) logic... lord have mercy! */
351 } else if (strB == null)
354 for (i = 0; i < length - 1; i++) {
355 if (strA[indexA + i] != strB[indexB + i])
359 return ((int) (strA[indexA + i] - strB[indexB + i]));
362 public static int Compare (string strA, int indexA, string strB, int indexB,
363 int length, bool ignoreCase)
368 return Compare (strA, indexA, strB, indexB, length);
370 if (length < 0 || indexA < 0 || indexB < 0)
371 throw new ArgumentOutOfRangeException ();
373 if (indexA > strA.Length || indexB > strB.Length)
374 throw new ArgumentOutOfRangeException ();
376 /* When will the hurting stop!?!? */
382 } else if (strB == null)
385 for (i = 0; i < length - 1; i++) {
386 if (Char.ToLower (strA[indexA + i]) != Char.ToLower (strB[indexB + i]))
390 return ((int) (strA[indexA + i] - strB[indexB + i]));
394 public static int Compare (string strA, int indexA, string strB, int indexB,
395 int length, bool ignoreCase, CultureInfo culture)
398 throw new ArgumentNullException ();
400 if (length < 0 || indexA < 0 || indexB < 0)
401 throw new ArgumentOutOfRangeException ();
403 if (indexA > strA.Length || indexB > strB.Length)
404 throw new ArgumentOutOfRangeException ();
406 /* I can't take it anymore! */
412 } else if (strB == null)
415 // FIXME: implement me
419 public static int CompareOrdinal (string strA, string strB)
423 /* Please God, make it stop! */
429 } else if (strB == null)
432 for (i = 0; i < strA.Length && i < strB.Length; i++) {
435 cA = tolowerordinal (strA[i]);
436 cB = tolowerordinal (strB[i]);
442 return ((int) (strA[i] - strB[i]));
445 public static int CompareOrdinal (string strA, int indexA, string strB, int indexB,
450 if (length < 0 || indexA < 0 || indexB < 0)
451 throw new ArgumentOutOfRangeException ();
458 } else if (strB == null)
461 for (i = 0; i < length; i++) {
464 cA = tolowerordinal (strA[indexA + i]);
465 cB = tolowerordinal (strB[indexB + i]);
471 return ((int) (strA[indexA + i] - strB[indexB + i]));
474 public int CompareTo (object obj)
476 return Compare (this, obj == null ? null : obj.ToString ());
479 public int CompareTo (string str)
481 return Compare (this, str);
484 public static string Concat (object arg)
486 return arg != null ? arg.ToString () : String.Empty;
489 public static string Concat (params object[] args)
496 throw new ArgumentNullException ();
498 strings = new string [args.Length];
501 foreach (object arg in args) {
502 /* use Empty for each null argument */
504 strings[i] = String.Empty;
506 strings[i] = arg.ToString ();
507 len += strings[i].length;
514 String res = new String (len);
517 for (int j = 0; j < strings.Length; j++)
518 for (int k = 0; k < strings[j].length; k++)
519 str[i++] = strings[j].c_str[k];
524 public static string Concat (params string[] values)
530 throw new ArgumentNullException ();
533 foreach (string value in values)
534 len += value != null ? value.Length : 0;
539 String res = new String (len);
542 foreach (string value in values) {
546 for (int j = 0; j < value.length; j++)
547 str[i++] = value.c_str[j];
553 public static string Concat (object arg0, object arg1)
555 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
556 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
558 return Concat (str0, str1);
561 public static string Concat (string str0, string str1)
571 len = str0.length + str1.length;
575 String res = new String (len);
578 for (i = 0; i < str0.length; i++)
579 concat[i] = str0.c_str[i];
580 for (j = 0 ; j < str1.length; j++)
581 concat[i + j] = str1.c_str[j];
586 public static string Concat (object arg0, object arg1, object arg2)
588 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
589 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
590 string str2 = arg2 != null ? arg2.ToString () : String.Empty;
592 return Concat (str0, str1, str2);
595 public static string Concat (string str0, string str1, string str2)
607 len = str0.length + str1.length + str2.length;
611 String res = new String (len);
614 for (i = 0; i < str0.length; i++)
615 concat[i] = str0.c_str[i];
616 for (j = 0; j < str1.length; j++)
617 concat[i + j] = str1.c_str[j];
618 for (k = 0; k < str2.length; k++)
619 concat[i + j + k] = str2.c_str[k];
624 public static string Concat (string str0, string str1, string str2, string str3)
638 len = str0.length + str1.length + str2.length + str3.length;
641 String res = new String (len);
644 for (i = 0; i < str0.length; i++)
645 concat[i] = str0.c_str[i];
646 for (j = 0; j < str1.length; j++)
647 concat[i + j] = str1.c_str[j];
648 for (k = 0; k < str2.length; k++)
649 concat[i + j + k] = str2.c_str[k];
650 for (l = 0; l < str3.length; l++)
651 concat[i + j + k + l] = str3.c_str[l];
656 public static string Copy (string str)
658 // FIXME: how do I *copy* a string if I can only have 1 of each?
660 throw new ArgumentNullException ();
665 public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
667 // LAMESPEC: should I null-terminate?
670 if (destination == null)
671 throw new ArgumentNullException ();
673 if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
674 throw new ArgumentOutOfRangeException ();
676 if (sourceIndex + count > this.length)
677 throw new ArgumentOutOfRangeException ();
679 if (destinationIndex + count > destination.Length)
680 throw new ArgumentOutOfRangeException ();
682 for (i = 0; i < count; i++)
683 destination[destinationIndex + i] = this.c_str[sourceIndex + i];
686 public bool EndsWith (string value)
688 bool endswith = true;
692 throw new ArgumentNullException ();
694 start = this.length - value.length;
698 for (i = start; i < this.length && endswith; i++)
699 endswith = this.c_str[i] == value.c_str[i - start];
704 public override bool Equals (object obj)
706 if (!(obj is String))
709 return this == (String) obj;
712 public bool Equals (string value)
714 return this == value;
717 public static bool Equals (string a, string b)
723 public static string Format (string format, object arg0)
725 // FIXME: implement me
726 return format+arg0.ToString();
730 public static string Format (string format, params object[] args)
732 // FIXME: implement me
733 Console.WriteLine (args[0].ToString());
734 if (args.Length == 1)
735 return format+args[0].ToString();
736 if (args.Length == 2)
737 return format+args[0].ToString()+args[1].ToString();
738 if (args.Length == 3)
739 return format+args[0].ToString()+args[1].ToString()+args[2].ToString();
740 if (args.Length == 4)
741 return format+args[0].ToString()+args[1].ToString()+args[2].ToString()+args[3].ToString();
742 Console.WriteLine ("String.Format with args: "+args.Length.ToString());
747 public static string Format (IFormatProvider provider, string format, params object[] args)
749 // FIXME: implement me
754 public static string Format (string format, object arg0, object arg1)
756 // FIXME: implement me
757 return format+arg0.ToString()+arg1.ToString();
761 public static string Format (string format, object arg0, object arg1, object arg2)
763 // FIXME: implement me
764 return format+arg0.ToString()+arg1.ToString()+arg2.ToString();
767 //public CharEnumerator GetEnumerator ()
769 public IEnumerator GetEnumerator ()
771 // FIXME: implement me
775 public override int GetHashCode ()
779 for (i = 0; i < length; ++i)
780 h = (h << 5) - h + c_str [i];
784 public TypeCode GetTypeCode ()
786 return TypeCode.String;
789 public int IndexOf (char value)
791 return IndexOf (value, 0, this.length);
794 public int IndexOf (string value)
796 return IndexOf (value, 0, this.length);
799 public int IndexOf (char value, int startIndex)
801 return IndexOf (value, startIndex, this.length - startIndex);
804 public int IndexOf (string value, int startIndex)
806 return IndexOf (value, startIndex, this.length - startIndex);
809 public int IndexOf (char value, int startIndex, int count)
813 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
814 throw new ArgumentOutOfRangeException ();
816 for (i = startIndex; i - startIndex < count; i++)
817 if (this.c_str[i] == value)
823 public int IndexOf (string value, int startIndex, int count)
826 throw new ArgumentNullException ();
828 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
829 throw new ArgumentOutOfRangeException ();
831 return BoyerMoore (this.c_str, value, startIndex, count);
834 for (i = startIndex; i - startIndex + value.Length <= count; ) {
835 if (this.c_str[i] == value[0]) {
839 for (j = 1; equal && j < value.Length; j++) {
840 equal = this.c_str[i + j] == value[j];
841 if (this.c_str[i + j] == value[0] && nexti == 0)
860 public int IndexOfAny (char[] values)
862 return IndexOfAny (values, 0, this.length);
865 public int IndexOfAny (char[] values, int startIndex)
867 return IndexOfAny (values, startIndex, this.length - startIndex);
870 public int IndexOfAny (char[] values, int startIndex, int count)
873 throw new ArgumentNullException ();
875 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
876 throw new ArgumentOutOfRangeException ();
878 for (int i = startIndex; i < startIndex + count; i++) {
879 for (int j = 0; j < strlen (values); j++) {
880 if (this.c_str[i] == values[j])
888 public string Insert (int startIndex, string value)
894 throw new ArgumentNullException ();
896 if (startIndex < 0 || startIndex > this.length)
897 throw new ArgumentOutOfRangeException ();
899 String res = new String (value.length + this.length);
902 for (i = 0; i < startIndex; i++)
903 str[i] = this.c_str[i];
904 for (j = 0; j < value.length; j++)
905 str[i + j] = value.c_str[j];
906 for ( ; i < this.length; i++)
907 str[i + j] = this.c_str[i];
912 [MethodImplAttribute(MethodImplOptions.InternalCall)]
913 public extern static string Intern (string str);
915 [MethodImplAttribute(MethodImplOptions.InternalCall)]
916 public extern static string IsInterned (string str);
918 public static string Join (string separator, string[] value)
920 return Join (separator, value, 0, value.Length);
923 public static string Join (string separator, string[] value, int startIndex, int count)
925 // LAMESPEC: msdn doesn't specify what happens when separator is null
929 if (separator == null || value == null)
930 throw new ArgumentNullException ();
932 if (startIndex + count > value.Length)
933 throw new ArgumentOutOfRangeException ();
936 for (i = startIndex, used = 0; used < count; i++, used++) {
938 len += separator.length;
940 len += value[i].length;
943 // We have no elements to join?
947 String res = new String (len);
950 for (i = 0; i < value[startIndex].length; i++)
951 str[i] = value[startIndex][i];
954 for (j = startIndex + 1; used < count; j++, used++) {
957 for (k = 0; k < separator.length; k++)
958 str[i++] = separator.c_str[k];
959 for (k = 0; k < value[j].length; k++)
960 str[i++] = value[j].c_str[k];
966 public int LastIndexOf (char value)
972 for (; i >= 0; i--) {
973 if (this.c_str[i] == value)
980 public int LastIndexOf (string value)
982 return LastIndexOf (value, this.length - 1, this.length);
985 public int LastIndexOf (char value, int startIndex)
987 if (startIndex < 0 || startIndex >= this.length)
988 throw new ArgumentOutOfRangeException ();
990 for (int i = startIndex; i >= 0; i--) {
991 if (this.c_str[i] == value)
998 public int LastIndexOf (string value, int startIndex)
1000 return LastIndexOf (value, startIndex, startIndex + 1);
1003 public int LastIndexOf (char value, int startIndex, int count)
1005 if (startIndex < 0 || count < 0)
1006 throw new ArgumentOutOfRangeException ();
1008 if (startIndex >= this.length || startIndex - count + 1 < 0)
1009 throw new ArgumentOutOfRangeException ();
1011 for (int i = startIndex; i > startIndex - count; i--) {
1012 if (this.c_str[i] == value)
1019 public int LastIndexOf (string value, int startIndex, int count)
1021 // LAMESPEC: currently I'm using startIndex as the 0-position in the comparison,
1022 // but maybe it's the end-position in MS's implementation?
1023 // msdn is unclear on this point. I think this is correct though.
1027 throw new ArgumentNullException ();
1029 if (startIndex < 0 || startIndex >= this.length)
1030 throw new ArgumentOutOfRangeException ();
1032 if (count < 0 || startIndex - count + 1 < 0)
1033 throw new ArgumentOutOfRangeException ();
1035 if (value == String.Empty)
1038 if (startIndex + value.length > this.length) {
1039 /* just a little optimization */
1042 start = this.length - value.length;
1043 count -= startIndex - start;
1047 // FIXME: use a reversed-unicode-safe-Boyer-Moore?
1048 len = value.length - 1;
1049 for (i = startIndex; i > startIndex - count; i--) {
1050 if (this.c_str[i + len] == value.c_str[len]) {
1054 for (j = len - 1; equal && j >= 0; j--)
1055 equal = this.c_str[i + j] == value.c_str[j];
1065 public int LastIndexOfAny (char[] values)
1067 return LastIndexOfAny (values, this.length - 1, this.length);
1070 public int LastIndexOfAny (char[] values, int startIndex)
1072 return LastIndexOfAny (values, startIndex, startIndex + 1);
1075 public int LastIndexOfAny (char[] values, int startIndex, int count)
1080 throw new ArgumentNullException ();
1082 if (startIndex < 0 || count < 0 || startIndex - count + 1 < 0)
1083 throw new ArgumentOutOfRangeException ();
1085 for (i = startIndex; i > startIndex - count; i--) {
1086 for (int j = 0; j < strlen (values); j++) {
1087 if (this.c_str[i] == values[j])
1095 public string PadLeft (int totalWidth)
1097 return PadLeft (totalWidth, ' ');
1100 public string PadLeft (int totalWidth, char padChar)
1106 throw new ArgumentException ();
1108 str = new char [totalWidth > this.length ? totalWidth : this.length];
1109 for (i = 0; i < totalWidth - this.length; i++)
1112 for (j = 0; j < this.length; i++, j++)
1113 str[i] = this.c_str[j];
1115 return new String (str);
1118 public string PadRight (int totalWidth)
1120 return PadRight (totalWidth, ' ');
1123 public string PadRight (int totalWidth, char padChar)
1129 throw new ArgumentException ();
1131 str = new char [totalWidth > this.length ? totalWidth : this.length];
1132 for (i = 0; i < this.length; i++)
1133 str[i] = this.c_str[i];
1135 for ( ; i < str.Length; i++)
1138 return new String (str);
1141 public string Remove (int startIndex, int count)
1146 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
1147 throw new ArgumentOutOfRangeException ();
1149 len = this.length - count;
1151 return String.Empty;
1153 String res = new String (len);
1155 for (i = 0; i < startIndex; i++)
1156 str[i] = this.c_str[i];
1157 for (j = i + count; j < this.length; j++)
1158 str[i++] = this.c_str[j];
1163 public string Replace (char oldChar, char newChar)
1168 String res = new String (length);
1170 for (i = 0; i < this.length; i++) {
1171 if (this.c_str[i] == oldChar)
1174 str[i] = this.c_str[i];
1180 public string Replace (string oldValue, string newValue)
1182 // LAMESPEC: msdn doesn't specify what to do if either args is null
1183 int index, len, i, j;
1186 if (oldValue == null || newValue == null)
1187 throw new ArgumentNullException ();
1189 // Use IndexOf in case I later rewrite it to use Boyer-Moore
1190 index = IndexOf (oldValue, 0);
1192 // This is the easy one ;-)
1193 return Substring (0, this.length);
1196 len = this.length - oldValue.length + newValue.length;
1198 return String.Empty;
1200 String res = new String (len);
1202 for (i = 0; i < index; i++)
1203 str[i] = this.c_str[i];
1204 for (j = 0; j < newValue.length; j++)
1205 str[i++] = newValue[j];
1206 for (j = index + oldValue.length; j < this.length; j++)
1207 str[i++] = this.c_str[j];
1212 private int splitme (char[] separators, int startIndex)
1214 /* this is basically a customized IndexOfAny() for the Split() methods */
1215 for (int i = startIndex; i < this.length; i++) {
1216 if (separators != null) {
1217 foreach (char sep in separators) {
1218 if (this.c_str[i] == sep)
1219 return i - startIndex;
1221 } else if (is_lwsp (this.c_str[i])) {
1222 return i - startIndex;
1229 public string[] Split (params char[] separator)
1233 * @separator: delimiting chars or null to split on whtspc
1235 * Returns: 1. An array consisting of a single
1236 * element (@this) if none of the delimiting
1237 * chars appear in @this. 2. An array of
1238 * substrings which are delimited by one of
1239 * the separator chars. 3. An array of
1240 * substrings separated by whitespace if
1241 * @separator is null. The Empty string should
1242 * be returned wherever 2 delimiting chars are
1245 // FIXME: would using a Queue be better?
1250 list = new ArrayList ();
1251 for (index = 0, len = 0; index < this.length; index += len + 1) {
1252 len = splitme (separator, index);
1253 len = len > -1 ? len : this.length - index;
1255 list.Add (String.Empty);
1260 str = new char [len];
1261 for (i = 0; i < len; i++)
1262 str[i] = this.c_str[index + i];
1264 list.Add (new String (str));
1268 strings = new string [list.Count];
1269 if (list.Count == 1) {
1270 /* special case for an array holding @this */
1273 for (index = 0; index < list.Count; index++)
1274 strings[index] = (string) list[index];
1280 public string[] Split (char[] separator, int maxCount)
1282 // FIXME: what to do if maxCount <= 0?
1283 // FIXME: would using Queue be better than ArrayList?
1286 int index, len, used;
1289 list = new ArrayList ();
1290 for (index = 0, len = 0; index < this.length && used < maxCount; index += len + 1) {
1291 len = splitme (separator, index);
1292 len = len > -1 ? len : this.length - index;
1294 list.Add (String.Empty);
1299 str = new char [len];
1300 for (i = 0; i < len; i++)
1301 str[i] = this.c_str[index + i];
1303 list.Add (new String (str));
1308 /* fit the remaining chunk of the @this into it's own element */
1309 if (index != this.length) {
1313 str = new char [this.length - index];
1314 for (i = index; i < this.length; i++)
1315 str[i - index] = this.c_str[i];
1317 list.Add (new String (str));
1320 strings = new string [list.Count];
1321 if (list.Count == 1) {
1322 /* special case for an array holding @this */
1325 for (index = 0; index < list.Count; index++)
1326 strings[index] = (string) list[index];
1332 public bool StartsWith (string value)
1334 bool startswith = true;
1338 throw new ArgumentNullException ();
1340 if (value.length > this.length)
1343 for (i = 0; i < value.length && startswith; i++)
1344 startswith = startswith && value.c_str[i] == this.c_str[i];
1349 public string Substring (int startIndex)
1354 if (startIndex < 0 || startIndex > this.length)
1355 throw new ArgumentOutOfRangeException ();
1357 len = this.length - startIndex;
1359 return String.Empty;
1360 String res = new String (len);
1362 for (i = startIndex; i < this.length; i++)
1363 str[i - startIndex] = this.c_str[i];
1368 public string Substring (int startIndex, int length)
1373 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1374 throw new ArgumentOutOfRangeException ();
1377 return String.Empty;
1379 String res = new String (length);
1381 for (i = startIndex; i < startIndex + length; i++)
1382 str[i - startIndex] = this.c_str[i];
1388 public bool ToBoolean (IFormatProvider provider)
1390 // FIXME: implement me
1391 throw new NotImplementedException ();
1395 public byte ToByte (IFormatProvider provider)
1397 // FIXME: implement me
1398 throw new NotImplementedException ();
1402 public char ToChar (IFormatProvider provider)
1404 // FIXME: implement me
1405 throw new NotImplementedException ();
1408 public char[] ToCharArray ()
1410 return ToCharArray (0, this.length);
1413 public char[] ToCharArray (int startIndex, int length)
1418 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1419 throw new ArgumentOutOfRangeException ();
1421 chars = new char [length];
1422 for (i = startIndex; i < length; i++)
1423 chars[i - startIndex] = this.c_str[i];
1429 public DateTime ToDateTime (IFormatProvider provider)
1431 // FIXME: implement me
1432 // return new DateTime (0);
1433 throw new NotImplementedException ();
1437 public decimal ToDecimal (IFormatProvider provider)
1439 // FIXME: implement me
1440 throw new NotImplementedException ();
1444 public double ToDouble (IFormatProvider provider)
1446 // FIXME: implement me
1447 throw new NotImplementedException ();
1451 public short ToInt16 (IFormatProvider provider)
1453 // FIXME: implement me
1454 throw new NotImplementedException ();
1458 public int ToInt32 (IFormatProvider provider)
1460 // FIXME: implement me
1461 throw new NotImplementedException ();
1465 public long ToInt64 (IFormatProvider provider)
1467 // FIXME: implement me
1468 throw new NotImplementedException ();
1471 public string ToLower ()
1476 String res = new String (length);
1478 for (i = 0; i < this.length; i++)
1479 str[i] = Char.ToLower (this.c_str[i]);
1485 public string ToLower (CultureInfo culture)
1487 // FIXME: implement me
1488 throw new NotImplementedException ();
1492 [CLSCompliant(false)][MonoTODO]
1493 public sbyte ToSByte (IFormatProvider provider)
1495 // FIXME: implement me
1496 throw new NotImplementedException ();
1500 public float ToSingle (IFormatProvider provider)
1502 // FIXME: implement me
1503 throw new NotImplementedException ();
1506 public override string ToString ()
1512 public string ToString (IFormatProvider format)
1514 // FIXME: implement me
1515 throw new NotImplementedException ();
1519 public object ToType (Type conversionType, IFormatProvider provider)
1521 // FIXME: implement me
1522 throw new NotImplementedException ();
1525 [CLSCompliant(false)][MonoTODO]
1526 public ushort ToUInt16 (IFormatProvider provider)
1528 // FIXME: implement me
1529 throw new NotImplementedException ();
1532 [CLSCompliant(false)][MonoTODO]
1533 public uint ToUInt32 (IFormatProvider provider)
1535 // FIXME: implement me
1536 throw new NotImplementedException ();
1539 [CLSCompliant(false)][MonoTODO]
1540 public ulong ToUInt64 (IFormatProvider provider)
1542 // FIXME: implement me
1543 throw new NotImplementedException ();
1546 public string ToUpper ()
1551 String res = new String (length);
1553 for (i = 0; i < this.length; i++)
1554 str[i] = Char.ToUpper (this.c_str[i]);
1560 public string ToUpper (CultureInfo culture)
1562 // FIXME: implement me
1563 throw new NotImplementedException ();
1566 public string Trim ()
1571 public string Trim (params char[] trimChars)
1577 for (begin = 0; matches && begin < this.length; begin++) {
1578 if (trimChars != null) {
1580 foreach (char c in trimChars) {
1581 matches = this.c_str[begin] == c;
1586 matches = is_lwsp (this.c_str[begin]);
1591 for (end = this.length - 1; matches && end > begin; end--) {
1592 if (trimChars != null) {
1594 foreach (char c in trimChars) {
1595 matches = this.c_str[end] == c;
1600 matches = is_lwsp (this.c_str[end]);
1605 return String.Empty;
1607 return Substring (begin, end - begin);
1610 public string TrimEnd (params char[] trimChars)
1612 bool matches = true;
1615 for (end = this.length; end > 0; end--) {
1616 if (trimChars != null) {
1618 foreach (char c in trimChars) {
1619 matches = this.c_str[end] == c;
1624 matches = is_lwsp (this.c_str[end]);
1629 return String.Empty;
1631 return Substring (0, end);
1634 public string TrimStart (params char[] trimChars)
1636 bool matches = true;
1639 for (begin = 0; matches && begin < this.length; begin++) {
1640 if (trimChars != null) {
1642 foreach (char c in trimChars) {
1643 matches = this.c_str[begin] == c;
1648 matches = is_lwsp (this.c_str[begin]);
1652 if (begin == this.length)
1653 return String.Empty;
1655 return Substring (begin, this.length - begin);
1659 public static bool operator ==(string a, string b)
1661 if ((object)a == null) {
1662 if ((object)b == null)
1666 if ((object)b == null)
1669 if (a.length != b.length)
1673 for (int i = 0; i < l; i++)
1674 if (a.c_str[i] != b.c_str[i])
1680 public static bool operator !=(string a, string b)