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;
31 public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable {
32 public static readonly string Empty = "";
37 unsafe public String (char *value)
41 // FIXME: can I do value.Length here?
45 for (i = 0; *(value + i) != '\0'; i++);
49 this.c_str = new char [this.length + 1];
50 for (i = 0; i < this.length; i++)
51 this.c_str[i] = *(value + i);
55 public String (char[] value)
59 // FIXME: value.Length includes the terminating null char?
60 this.length = value != null ? strlen (value): 0;
61 this.c_str = new char [this.length + 1];
62 for (i = 0; i < this.length; i++)
63 this.c_str[i] = value[i];
67 unsafe public String (sbyte *value)
69 // FIXME: consider unicode?
72 // FIXME: can I do value.Length here? */
76 for (i = 0; *(value + i) != '\0'; i++);
80 this.c_str = new char [this.length + 1];
81 for (i = 0; i < this.length; i++)
82 this.c_str[i] = (char) *(value + i);
86 public String (char c, int count)
91 this.c_str = new char [count + 1];
92 for (i = 0; i < count; i++)
97 unsafe public String (char *value, int startIndex, int length)
101 if (value == null && startIndex != 0 && length != 0)
102 throw new ArgumentNullException ();
104 if (startIndex < 0 || length < 0)
105 throw new ArgumentOutOfRangeException ();
107 this.length = length;
108 this.c_str = new char [length + 1];
109 for (i = 0; i < length; i++)
110 this.c_str[i] = *(value + startIndex + i);
111 this.c_str[i] = '\0';
114 public String (char[] value, int startIndex, int length)
118 if (value == null && startIndex != 0 && length != 0)
119 throw new ArgumentNullException ();
121 if (startIndex < 0 || length < 0)
122 throw new ArgumentOutOfRangeException ();
124 this.length = length;
125 this.c_str = new char [length + 1];
126 for (i = 0; i < length; i++)
127 this.c_str[i] = value[startIndex + i];
128 this.c_str[i] = '\0';
131 unsafe public String (sbyte *value, int startIndex, int length)
133 // FIXME: consider unicode?
136 if (value == null && startIndex != 0 && length != 0)
137 throw new ArgumentNullException ();
139 if (startIndex < 0 || length < 0)
140 throw new ArgumentOutOfRangeException ();
142 this.length = length;
143 this.c_str = new char [length + 1];
144 for (i = 0; i < length; i++)
145 this.c_str[i] = (char) *(value + startIndex + i);
146 this.c_str[i] = '\0';
149 unsafe public String (sbyte *value, int startIndex, int length, Encoding enc)
151 // FIXME: implement me
156 // FIXME: is there anything we need to do here?
157 /*base.Finalize ();*/
167 // FIXME: is this correct syntax??
168 public char this [int index] {
170 if (index > this.length)
171 throw new ArgumentOutOfRangeException ();
173 return this.c_str[index];
177 // Private helper methods
178 private static int strlen (char[] str)
180 // FIXME: if str.Length includes terminating null char, then return (str.Length - 1)
184 private static char tolowerordinal (char c)
186 // FIXME: implement me
190 private static bool is_lwsp (char c)
192 /* this comes from the msdn docs for String.Trim() */
193 if ((c >= '\x9' && c <= '\xD') || c == '\x20' || c == '\xA0' ||
194 (c >= '\x2000' && c <= '\x200B') || c == '\x3000' || c == '\xFEFF')
200 private static int BoyerMoore (char[] haystack, string needle, int startIndex, int count)
202 /* (hopefully) Unicode-safe Boyer-Moore implementation */
203 int[] skiptable = new int[65536]; /* our unicode-safe skip-table */
204 int h, n, he, ne, hc, nc, i;
206 if (haystack == null || needle == null)
207 throw new ArgumentNullException ();
209 /* if the search buffer is shorter than the pattern buffer, we can't match */
210 if (count < needle.Length)
213 /* return an instant match if the pattern is 0-length */
214 if (needle.Length == 0)
217 /* set a pointer at the end of each string */
218 ne = needle.Length - 1; /* position of char before '\0' */
219 he = startIndex + count; /* position of last valid char */
221 /* init the skip table with the pattern length */
222 for (i = 0; i < 65536; i++)
223 skiptable[i] = needle.Length;
225 /* set the skip value for the chars that *do* appear in the
226 * pattern buffer (needle) to the distance from the index to
227 * the end of the pattern buffer. */
228 for (nc = 0; nc < ne; nc++)
229 skiptable[(int) needle[nc]] = ne - nc;
232 while (count >= needle.Length) {
233 hc = h + needle.Length - 1; /* set the haystack compare pointer */
234 nc = ne; /* set the needle compare pointer */
236 /* work our way backwards until they don't match */
237 for (i = 0; nc > 0; nc--, hc--, i++)
238 if (needle[nc] != haystack[hc])
241 if (needle[nc] != haystack[hc]) {
242 n = skiptable[(int) haystack[hc]] - i;
253 public object Clone ()
255 // FIXME: implement me
259 public static int Compare (string strA, string strB)
263 /* Does this remind anyone of the nautilus string.h wrappers? ;-) */
269 } else if (strB == null)
272 for (i = 0; strA[i] == strB[i] && strA[i] != '\0'; i++);
274 return ((int) (strA[i] - strB[i]));
277 public static int Compare (string strA, string strB, bool ignoreCase)
282 return Compare (strA, strB);
285 * And here I thought Eazel developers were on crack...
286 * if a string is null it should pelt the programmer with
287 * ArgumentNullExceptions, damnit!
294 } else if (strB == null)
297 for (i = 0; strA[i] != '\0' && strB[i] != '\0'; i++) {
298 if (Char.ToLower (strA[i]) != Char.ToLower (strB[i]))
302 return ((int) (strA[i] - strB[i]));
305 public static int Compare (string strA, string strB, bool ignoreCase, CultureInfo culture)
307 // FIXME: implement me
311 public static int Compare (string strA, int indexA, string strB, int indexB, int length)
315 if (length < 0 || indexA < 0 || indexB < 0)
316 throw new ArgumentOutOfRangeException ();
318 if (indexA > strA.Length || indexB > strB.Length)
319 throw new ArgumentOutOfRangeException ();
321 /* And again with the ("" > null) logic... lord have mercy! */
327 } else if (strB == null)
330 for (i = 0; i < length - 1; i++) {
331 if (strA[indexA + i] != strB[indexB + i])
335 return ((int) (strA[indexA + i] - strB[indexB + i]));
338 public static int Compare (string strA, int indexA, string strB, int indexB,
339 int length, bool ignoreCase)
344 return Compare (strA, indexA, strB, indexB, length);
346 if (length < 0 || indexA < 0 || indexB < 0)
347 throw new ArgumentOutOfRangeException ();
349 if (indexA > strA.Length || indexB > strB.Length)
350 throw new ArgumentOutOfRangeException ();
352 /* When will the hurting stop!?!? */
358 } else if (strB == null)
361 for (i = 0; i < length - 1; i++) {
362 if (Char.ToLower (strA[indexA + i]) != Char.ToLower (strB[indexB + i]))
366 return ((int) (strA[indexA + i] - strB[indexB + i]));
369 public static int Compare (string strA, int indexA, string strB, int indexB,
370 int length, bool ignoreCase, CultureInfo culture)
373 throw new ArgumentNullException ();
375 if (length < 0 || indexA < 0 || indexB < 0)
376 throw new ArgumentOutOfRangeException ();
378 if (indexA > strA.Length || indexB > strB.Length)
379 throw new ArgumentOutOfRangeException ();
381 /* I can't take it anymore! */
387 } else if (strB == null)
389 // FIXME: implement me
393 public static int CompareOrdinal (string strA, string strB)
397 /* Please God, make it stop! */
403 } else if (strB == null)
406 for (i = 0; strA[i] != '\0'; i++) {
409 cA = tolowerordinal (strA[i]);
410 cB = tolowerordinal (strB[i]);
416 return ((int) (strA[i] - strB[i]));
419 public static int CompareOrdinal (string strA, int indexA, string strB, int indexB,
424 if (length < 0 || indexA < 0 || indexB < 0)
425 throw new ArgumentOutOfRangeException ();
433 } else if (strB == null)
436 for (i = 0; i < length; i++) {
439 cA = tolowerordinal (strA[indexA + i]);
440 cB = tolowerordinal (strB[indexB + i]);
446 return ((int) (strA[indexA + i] - strB[indexB + i]));
449 public int CompareTo (object obj)
451 return Compare (this, obj == null ? null : obj.ToString ());
454 public int CompareTo (string str)
456 return Compare (this, str);
459 public static string Concat (object arg)
461 return arg != null ? arg.ToString () : String.Empty;
464 public static string Concat (params object[] args)
471 throw new ArgumentNullException ();
473 strings = new string [args.Length];
476 foreach (object arg in args) {
477 /* use Empty for each null argument */
479 strings[i] = String.Empty;
481 strings[i] = arg.ToString ();
482 len += strings[i].Length;
489 str = new char [len + 1];
491 for (int j = 0; j < strings.Length; j++)
492 for (int k = 0; k < strings[j].Length; k++)
493 str[i++] = strings[j][k];
496 return new String (str);
499 public static string Concat (params string[] values)
505 throw new ArgumentNullException ();
508 foreach (string value in values)
509 len += value != null ? value.Length : 0;
514 str = new char [len + 1];
516 foreach (string value in values) {
520 for (int j = 0; j < value.Length; j++)
525 return new String (str);
528 public static string Concat (object arg0, object arg1)
530 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
531 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
533 return Concat (str0, str1);
536 public static string Concat (string str0, string str1)
546 len = str0.Length + str1.Length;
550 concat = new char [len + 1];
551 for (i = 0; i < str0.Length; i++)
553 for (j = 0 ; j < str1.Length; j++)
554 concat[i + j] = str1[j];
557 return new String (concat);
560 public static string Concat (object arg0, object arg1, object arg2)
562 string str0 = arg0 != null ? arg0.ToString () : String.Empty;
563 string str1 = arg1 != null ? arg1.ToString () : String.Empty;
564 string str2 = arg2 != null ? arg2.ToString () : String.Empty;
566 return Concat (str0, str1, str2);
569 public static string Concat (string str0, string str1, string str2)
581 len = str0.Length + str1.Length + str2.Length;
585 concat = new char [len + 1];
586 for (i = 0; i < str0.Length; i++)
588 for (j = 0; j < str1.Length; j++)
589 concat[i + j] = str1[j];
590 for (k = 0; k < str2.Length; k++)
591 concat[i + j + k] = str2[k];
594 return new String (concat);
597 public static string Concat (string str0, string str1, string str2, string str3)
611 len = str0.Length + str1.Length + str2.Length + str3.Length;
615 concat = new char [len + 1];
616 for (i = 0; i < str0.Length; i++)
618 for (j = 0; j < str1.Length; j++)
619 concat[i + j] = str1[j];
620 for (k = 0; k < str2.Length; k++)
621 concat[i + j + k] = str2[k];
622 for (l = 0; l < str3.Length; l++)
623 concat[i + j + k + l] = str3[l];
626 return new String (concat);
629 public static string Copy (string str)
631 // FIXME: how do I *copy* a string if I can only have 1 of each?
633 throw new ArgumentNullException ();
638 public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
640 // LAMESPEC: should I null-terminate?
643 if (destination == null)
644 throw new ArgumentNullException ();
646 if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
647 throw new ArgumentOutOfRangeException ();
649 if (sourceIndex + count > this.length)
650 throw new ArgumentOutOfRangeException ();
652 if (destinationIndex + count > destination.Length)
653 throw new ArgumentOutOfRangeException ();
655 for (i = 0; i < count; i++)
656 destination[destinationIndex + i] = this.c_str[sourceIndex + i];
659 public bool EndsWith (string value)
661 bool endswith = true;
665 throw new ArgumentNullException ();
667 start = this.length - value.Length;
671 for (i = start; i < this.length && endswith; i++)
672 endswith = this.c_str[i] == value[i - start];
677 public override bool Equals (object obj)
679 if (!(obj is String))
682 return this == (String) obj;
685 public bool Equals (string value)
687 return this == value;
690 public static bool Equals (string a, string b)
695 public static string Format (string format, object arg0)
697 // FIXME: implement me
701 public static string Format (string format, params object[] args)
703 // FIXME: implement me
707 public static string Format (IFormatProvider provider, string format, params object[] args)
709 // FIXME: implement me
713 public static string Format (string format, object arg0, object arg1)
715 // FIXME: implement me
719 public static string Format (string format, object arg0, object arg1, object arg2)
721 // FIXME: implement me
725 //public CharEnumerator GetEnumerator ()
726 public IEnumerator GetEnumerator ()
728 // FIXME: implement me
732 public override int GetHashCode ()
734 // FIXME: implement me
738 public new Type GetType ()
740 // FIXME: implement me
744 public TypeCode GetTypeCode ()
746 // FIXME: implement me
750 public int IndexOf (char value)
752 return IndexOf (value, 0, this.length);
755 public int IndexOf (string value)
757 return IndexOf (value, 0, this.length);
760 public int IndexOf (char value, int startIndex)
762 return IndexOf (value, startIndex, this.length - startIndex);
765 public int IndexOf (string value, int startIndex)
767 return IndexOf (value, startIndex, this.length - startIndex);
770 public int IndexOf (char value, int startIndex, int count)
774 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
775 throw new ArgumentOutOfRangeException ();
777 for (i = startIndex; i - startIndex < count; i++)
778 if (this.c_str[i] == value)
784 public int IndexOf (string value, int startIndex, int count)
789 throw new ArgumentNullException ();
791 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
792 throw new ArgumentOutOfRangeException ();
794 return BoyerMoore (this.c_str, value, startIndex, count);
796 for (i = startIndex; i - startIndex + value.Length <= count; ) {
797 if (this.c_str[i] == value[0]) {
801 for (j = 1; equal && value[j] != '\0'; j++) {
802 equal = this.c_str[i + j] == value[j];
803 if (this.c_str[i + j] == value[0] && nexti == 0)
822 public int IndexOfAny (char[] values)
824 return IndexOfAny (values, 0, this.length);
827 public int IndexOfAny (char[] values, int startIndex)
829 return IndexOfAny (values, startIndex, this.length - startIndex);
832 public int IndexOfAny (char[] values, int startIndex, int count)
835 throw new ArgumentNullException ();
837 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
838 throw new ArgumentOutOfRangeException ();
840 for (int i = startIndex; i < startIndex + count; i++) {
841 for (int j = 0; j < strlen (values); j++) {
842 if (this.c_str[i] == values[j])
850 public string Insert (int startIndex, string value)
856 throw new ArgumentNullException ();
858 if (startIndex < 0 || startIndex > this.length)
859 throw new ArgumentOutOfRangeException ();
861 str = new char [value.Length + this.length + 1];
862 for (i = 0; i < startIndex; i++)
863 str[i] = this.c_str[i];
864 for (j = 0; j < value.Length; j++)
865 str[i + j] = value[j];
866 for ( ; i < this.length; i++)
867 str[i + j] = this.c_str[i];
870 return new String (str);
873 public static string Intern (string str)
876 throw new ArgumentNullException ();
877 // FIXME: implement me
881 public static string IsInterned (string str)
884 throw new ArgumentNullException ();
885 // FIXME: implement me
889 public static string Join (string separator, string[] value)
891 return Join (separator, value, 0, value.Length);
894 public static string Join (string separator, string[] value, int startIndex, int count)
896 // LAMESPEC: msdn doesn't specify what happens when separator is null
900 if (separator == null || value == null)
901 throw new ArgumentNullException ();
903 if (startIndex + count > value.Length)
904 throw new ArgumentOutOfRangeException ();
907 for (i = startIndex, used = 0; used < count; i++, used++) {
909 len += separator.Length;
911 len += value[i].Length;
914 // We have no elements to join?
918 str = new char [len + 1];
919 for (i = 0; i < value[startIndex].Length; i++)
920 str[i] = value[startIndex][i];
923 for (j = startIndex + 1; used < count; j++, used++) {
926 for (k = 0; k < separator.Length; k++)
927 str[i++] = separator[k];
928 for (k = 0; k < value[j].Length; k++)
929 str[i++] = value[j][k];
933 return new String (str);
936 public int LastIndexOf (char value)
938 for (int i = this.length; i >= 0; i--) {
939 if (this.c_str[i] == value)
946 public int LastIndexOf (string value)
948 return LastIndexOf (value, this.length, this.length);
951 public int LastIndexOf (char value, int startIndex)
953 if (startIndex < 0 || startIndex > this.length)
954 throw new ArgumentOutOfRangeException ();
956 for (int i = startIndex; i >= 0; i--) {
957 if (this.c_str[i] == value)
964 public int LastIndexOf (string value, int startIndex)
966 return LastIndexOf (value, startIndex, this.length);
969 public int LastIndexOf (char value, int startIndex, int count)
971 if (startIndex < 0 || count < 0)
972 throw new ArgumentOutOfRangeException ();
974 if (startIndex > this.length || startIndex - count < 0)
975 throw new ArgumentOutOfRangeException ();
977 for (int i = startIndex; i >= startIndex - count; i--) {
978 if (this.c_str[i] == value)
985 public int LastIndexOf (string value, int startIndex, int count)
987 // LAMESPEC: currently I'm using startIndex as the 0-position in the comparison,
988 // but maybe it's the end-position in MS's implementation?
989 // msdn is unclear on this point. I think this is correct though.
993 throw new ArgumentNullException ();
995 if (startIndex < 0 || startIndex > this.length)
996 throw new ArgumentOutOfRangeException ();
998 if (count < 0 || startIndex - count < 0)
999 throw new ArgumentOutOfRangeException ();
1001 if (value == String.Empty)
1004 if (startIndex + value.Length > this.length) {
1005 /* just a little optimization */
1008 start = this.length - value.Length;
1009 count -= startIndex - start;
1013 // FIXME: use a reversed-unicode-safe-Boyer-Moore?
1014 len = value.Length - 1;
1015 for (i = startIndex; i >= startIndex - count; i--) {
1016 if (this.c_str[i + len] == value[len]) {
1020 for (j = len - 1; equal && j >= 0; j--)
1021 equal = this.c_str[i + j] == value[j];
1031 public int LastIndexOfAny (char[] values)
1033 return LastIndexOfAny (values, this.length, this.length);
1036 public int LastIndexOfAny (char[] values, int startIndex)
1038 return LastIndexOfAny (values, startIndex, startIndex);
1041 public int LastIndexOfAny (char[] values, int startIndex, int count)
1046 throw new ArgumentNullException ();
1048 if (startIndex < 0 || count < 0 || startIndex - count < 0)
1049 throw new ArgumentOutOfRangeException ();
1051 for (i = startIndex; i >= startIndex - count; i--) {
1052 for (int j = 0; j < strlen (values); j++) {
1053 if (this.c_str[i] == values[j])
1061 public string PadLeft (int totalWidth)
1063 return PadLeft (totalWidth, ' ');
1066 public string PadLeft (int totalWidth, char padChar)
1072 throw new ArgumentException ();
1074 str = new char [totalWidth > this.length ? totalWidth : this.length + 1];
1075 for (i = 0; i < totalWidth - this.length; i++)
1078 for (j = 0; j < this.length; i++, j++)
1079 str[i] = this.c_str[j];
1083 return new String (str);
1086 public string PadRight (int totalWidth)
1088 return PadRight (totalWidth, ' ');
1091 public string PadRight (int totalWidth, char padChar)
1097 throw new ArgumentException ();
1099 str = new char [totalWidth > this.length ? totalWidth : this.length + 1];
1100 for (i = 0; i < this.length; i++)
1101 str[i] = this.c_str[i];
1103 for ( ; i < str.Length; i++)
1108 return new String (str);
1111 public string Remove (int startIndex, int count)
1116 if (startIndex < 0 || count < 0 || startIndex + count > this.length)
1117 throw new ArgumentOutOfRangeException ();
1119 len = this.length - count;
1121 return String.Empty;
1123 str = new char [len + 1];
1124 for (i = 0; i < startIndex; i++)
1125 str[i] = this.c_str[i];
1126 for (j = i + count; j < this.length; j++)
1127 str[i++] = this.c_str[j];
1130 return new String (str);
1133 public string Replace (char oldChar, char newChar)
1138 str = new char [this.length + 1];
1139 for (i = 0; i < this.length; i++) {
1140 if (this.c_str[i] == oldChar)
1143 str[i] = this.c_str[i];
1147 return new String (str);
1150 public string Replace (string oldValue, string newValue)
1152 // LAMESPEC: msdn doesn't specify what to do if either args is null
1153 int index, len, i, j;
1156 if (oldValue == null || newValue == null)
1157 throw new ArgumentNullException ();
1159 // Use IndexOf in case I later rewrite it to use Boyer-Moore
1160 index = IndexOf (oldValue, 0);
1162 // This is the easy one ;-)
1163 return Substring (0, this.length);
1166 len = this.length - oldValue.Length + newValue.Length;
1168 return String.Empty;
1170 str = new char [len + 1];
1171 for (i = 0; i < index; i++)
1172 str[i] = this.c_str[i];
1173 for (j = 0; j < newValue.Length; j++)
1174 str[i++] = newValue[j];
1175 for (j = index + oldValue.Length; j < this.length; j++)
1176 str[i++] = this.c_str[j];
1179 return new String (str);
1182 private int splitme (char[] separators, int startIndex)
1184 /* this is basically a customized IndexOfAny() for the Split() methods */
1185 for (int i = startIndex; i < this.length; i++) {
1186 if (separators != null) {
1187 foreach (char sep in separators) {
1188 if (this.c_str[i] == sep)
1189 return i - startIndex;
1191 } else if (is_lwsp (this.c_str[i])) {
1192 return i - startIndex;
1199 public string[] Split (params char[] separator)
1203 * @separator: delimiting chars or null to split on whtspc
1205 * Returns: 1. An array consisting of a single
1206 * element (@this) if none of the delimiting
1207 * chars appear in @this. 2. An array of
1208 * substrings which are delimited by one of
1209 * the separator chars. 3. An array of
1210 * substrings separated by whitespace if
1211 * @separator is null. The Empty string should
1212 * be returned wherever 2 delimiting chars are
1215 // FIXME: would using a Queue be better?
1220 list = new ArrayList ();
1221 for (index = 0, len = 0; index < this.length; index += len + 1) {
1222 len = splitme (separator, index);
1223 len = len > -1 ? len : this.length - index;
1225 list.Add (String.Empty);
1230 str = new char [len + 1];
1231 for (i = 0; i < len; i++)
1232 str[i] = this.c_str[index + i];
1235 list.Add (new String (str));
1239 strings = new string [list.Count];
1240 if (list.Count == 1) {
1241 /* special case for an array holding @this */
1244 for (index = 0; index < list.Count; index++)
1245 strings[index] = (string) list[index];
1251 public string[] Split (char[] separator, int maxCount)
1253 // FIXME: what to do if maxCount <= 0?
1254 // FIXME: would using Queue be better than ArrayList?
1257 int index, len, used;
1260 list = new ArrayList ();
1261 for (index = 0, len = 0; index < this.length && used < maxCount; index += len + 1) {
1262 len = splitme (separator, index);
1263 len = len > -1 ? len : this.length - index;
1265 list.Add (String.Empty);
1270 str = new char [len + 1];
1271 for (i = 0; i < len; i++)
1272 str[i] = this.c_str[index + i];
1275 list.Add (new String (str));
1280 /* fit the remaining chunk of the @this into it's own element */
1281 if (index != this.length) {
1285 str = new char [this.length - index + 1];
1286 for (i = index; i < this.length; i++)
1287 str[i - index] = this.c_str[i];
1288 str[i - index] = '\0';
1290 list.Add (new String (str));
1293 strings = new string [list.Count];
1294 if (list.Count == 1) {
1295 /* special case for an array holding @this */
1298 for (index = 0; index < list.Count; index++)
1299 strings[index] = (string) list[index];
1305 public bool StartsWith (string value)
1307 bool startswith = true;
1311 throw new ArgumentNullException ();
1313 if (value.Length > this.length)
1316 for (i = 0; i < value.Length && startswith; i++)
1317 startswith = startswith && value[i] == this.c_str[i];
1322 public string Substring (int startIndex)
1327 if (startIndex < 0 || startIndex > this.length)
1328 throw new ArgumentOutOfRangeException ();
1330 len = this.length - startIndex;
1332 return String.Empty;
1334 str = new char [len + 1];
1335 for (i = startIndex; i < this.length; i++)
1336 str[i - startIndex] = this.c_str[i];
1339 return new String (str);
1342 public string Substring (int startIndex, int length)
1347 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1348 throw new ArgumentOutOfRangeException ();
1351 return String.Empty;
1353 str = new char [length + 1];
1354 for (i = startIndex; i < startIndex + length; i++)
1355 str[i - startIndex] = this.c_str[i];
1358 return new String (str);
1361 public bool ToBoolean (IFormatProvider provider)
1363 // FIXME: implement me
1367 public byte ToByte (IFormatProvider provider)
1369 // FIXME: implement me
1373 public char ToChar (IFormatProvider provider)
1375 // FIXME: implement me
1379 public char[] ToCharArray ()
1381 return ToCharArray (0, this.length);
1384 public char[] ToCharArray (int startIndex, int length)
1389 if (startIndex < 0 || length < 0 || startIndex + length > this.length)
1390 throw new ArgumentOutOfRangeException ();
1392 chars = new char [length + 1];
1393 for (i = startIndex; i < length; i++)
1394 chars[i - startIndex] = this.c_str[i];
1396 chars[length] = '\0';
1401 public DateTime ToDateTime (IFormatProvider provider)
1403 // FIXME: implement me
1405 return new DateTime (0);
1408 public decimal ToDecimal (IFormatProvider provider)
1410 // FIXME: implement me
1414 public double ToDouble (IFormatProvider provider)
1416 // FIXME: implement me
1420 public short ToInt16 (IFormatProvider provider)
1422 // FIXME: implement me
1426 public int ToInt32 (IFormatProvider provider)
1428 // FIXME: implement me
1432 public long ToInt64 (IFormatProvider provider)
1434 // FIXME: implement me
1438 public string ToLower ()
1443 str = new char [this.length + 1];
1444 for (i = 0; i < this.length; i++)
1445 str[i] = Char.ToLower (this.c_str[i]);
1448 return new String (str);
1451 public string ToLower (CultureInfo culture)
1453 // FIXME: implement me
1457 public sbyte ToSByte (IFormatProvider provider)
1459 // FIXME: implement me
1463 public float ToSingle (IFormatProvider provider)
1465 // FIXME: implement me
1469 public override string ToString ()
1471 return Substring (0, this.length);
1474 public string ToString (IFormatProvider format)
1476 // FIXME: implement me
1480 public object ToType (Type conversionType, IFormatProvider provider)
1482 // FIXME: implement me
1486 public ushort ToUInt16 (IFormatProvider provider)
1488 // FIXME: implement me
1492 public uint ToUInt32 (IFormatProvider provider)
1494 // FIXME: implement me
1498 public ulong ToUInt64 (IFormatProvider provider)
1500 // FIXME: implement me
1504 public string ToUpper ()
1509 str = new char [this.length + 1];
1510 for (i = 0; i < this.length; i++)
1511 str[i] = Char.ToUpper (this.c_str[i]);
1514 return new String (str);
1517 public string ToUpper (CultureInfo culture)
1519 // FIXME: implement me
1523 public string Trim ()
1528 public string Trim (params char[] trimChars)
1534 for (begin = 0; matches && begin < this.length; begin++) {
1535 if (trimChars != null) {
1537 foreach (char c in trimChars)
1538 matches = this.c_str[begin] == c;
1540 matches = is_lwsp (this.c_str[begin]);
1545 for (end = this.length; end > begin; end--) {
1546 if (trimChars != null) {
1548 foreach (char c in trimChars)
1549 matches = this.c_str[end] == c;
1551 matches = is_lwsp (this.c_str[end]);
1556 return String.Empty;
1558 return Substring (begin, end - begin);
1561 public string TrimEnd (params char[] trimChars)
1563 bool matches = true;
1566 for (end = this.length; end > 0; end--) {
1567 if (trimChars != null) {
1569 foreach (char c in trimChars)
1570 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;
1593 matches = is_lwsp (this.c_str[begin]);
1597 if (begin == this.length)
1598 return String.Empty;
1600 return Substring (begin, this.length - begin);
1604 public static bool operator ==(string a, string b)
1606 if (a.length != b.length)
1610 for (int i = 0; i < l; i++)
1611 if (a.c_str [i] != b.c_str [i])
1617 public static bool operator !=(string a, string b)