use internal call constructors
[mono.git] / mcs / class / corlib / System / String.cs
1 //
2 // System.String.cs
3 //
4 // Authors:
5 //        Patrik Torstensson (patrik.torstensson@labs2.com)
6 //   Jeffrey Stedfast (fejj@ximian.com)
7 //   Dan Lewis (dihlewis@yahoo.co.uk)
8 //
9 // (C) 2001 Ximian, Inc.  http://www.ximian.com
10 //
11
12 using System;
13 using System.Text;
14 using System.Collections;
15 using System.Globalization;
16 using System.Runtime.CompilerServices;
17
18 namespace System {
19         public sealed class String : IConvertible, IComparable, ICloneable, IEnumerable {
20                 private int length;
21
22                 public static readonly String Empty = "";
23
24                 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
25                 unsafe public extern String(char *value);
26
27                 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
28                 unsafe public extern String(char *value, int sindex, int length);
29     
30                 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
31                 unsafe public extern String(sbyte *value);
32
33                 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
34                 unsafe public extern String(sbyte *value, int sindex, int length);
35
36                 [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
37                 unsafe public extern String(sbyte *value, int sindex, int length, Encoding enc);
38
39                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
40                 public extern String(char [] val, int sindex, int length);
41                 
42                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
43                 public extern String(char [] val);
44
45                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
46                 public extern String(char c, int count);
47         
48                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
49                 public extern override int GetHashCode();
50
51                 public static bool Equals(String str1, String str2) {
52                         if ((Object) str1 == (Object) str2)
53                                 return true;
54             
55                         if (null == (Object) str1 || null == (Object) str2)
56                                 return false;
57                         if (str1.length != str2.length)
58                                 return false;
59     
60                         return Compare(str1, 0, str2, 0, str1.length, false) == 0;
61                 }
62
63                 public static bool operator == (String str1, String str2) {
64                         return Equals(str1, str2);
65                 }
66
67                 public static bool operator != (String str1, String str2) {
68                         return !Equals(str1, str2);
69                 }
70
71                 public override bool Equals(Object obj) {
72                         if (null == obj)
73                                 return false;
74
75                         if (!(obj is String))
76                                 return false;
77
78                         return Compare (this, (String)obj, false) == 0;
79                 }
80
81                 public bool Equals(String value) {
82                         if (null == value)
83                                 return false;
84
85                         if (length != value.length)
86                                 return false;
87                         return Compare (this, 0, value, 0, length, false) == 0;
88                 }
89
90                 [IndexerName("Chars")]
91                 public extern char this[int index] {
92                         [MethodImplAttribute(MethodImplOptions.InternalCall)]
93                         get;
94                 }
95
96                 public Object Clone() {
97                         return this;
98                 }
99
100                 public TypeCode GetTypeCode () {
101                         return TypeCode.String;
102                 }
103
104                 public void CopyTo(int sindex, char[] dest, int dindex, int count) {
105                         // LAMESPEC: should I null-terminate?
106                         
107                         if (dest == null)
108                                 throw new ArgumentNullException();
109
110                         if (sindex < 0 || dindex < 0 || count < 0)
111                                 throw new ArgumentOutOfRangeException (); 
112
113                         if (sindex + count > Length)
114                                 throw new ArgumentOutOfRangeException ();
115
116                         if (dindex + count > dest.Length)
117                                 throw new ArgumentOutOfRangeException ();
118
119                         InternalCopyTo(sindex, dest, dindex, count);
120                 }
121
122                 public char[] ToCharArray() {
123                         return ToCharArray(0, length);
124                 }
125
126                 public char[] ToCharArray(int sindex, int length) {
127                         if (sindex < 0 || length < 0 || sindex + length > this.length)
128                                 throw new ArgumentOutOfRangeException (); 
129
130                         char [] tmp = new char[length];
131
132                         InternalCopyTo(sindex, tmp, 0, length);
133
134                         return tmp;
135                 }
136                 
137                 public String [] Split(params char [] separator) {
138                         return Split(separator, Int32.MaxValue);
139                 }
140
141                 public String[] Split(char[] separator, int count) {
142                         if (null == separator) {
143                                 separator = WhiteChars;
144                         }
145
146                         if (count < 0)
147                                 throw new ArgumentOutOfRangeException ();
148
149                         if (count == 0) 
150                                 return new String[1] { ToString() };
151
152                         return InternalSplit(separator, count);
153                 }
154
155                 public String Substring (int sindex) {
156                         if (sindex < 0 || sindex > this.length) {
157                                 Console.WriteLine("Substring({0}) = {2}\n", sindex, this.length, this);
158                                 throw new ArgumentOutOfRangeException();
159                         }
160
161                         string tmp = InternalAllocateStr(this.length - sindex);
162                         InternalStrcpy(tmp, 0, this, sindex, length - sindex);
163                         
164                         return tmp;
165                 }
166
167                 public String Substring (int sindex, int length) {
168                         if (length < 0 || sindex < 0 || sindex + length > this.length) {
169                                 Console.WriteLine("Substring({0}, {1}) = {2}\n", sindex, length, this.ToString());
170                                 throw new ArgumentOutOfRangeException();
171                         }
172
173                         if (length == 0)
174                                 return String.Empty;
175
176                         string tmp = InternalAllocateStr(length);
177                         InternalStrcpy(tmp, 0, this, sindex, length);
178
179                         return tmp;
180                 }       
181
182                 private static readonly char[] WhiteChars = {  (char) 0x9, (char) 0xA, (char) 0xB, (char) 0xC, (char) 0xD, (char) 0x20, (char) 0xA0, (char) 0x2000, (char) 0x2001, (char) 0x2002, (char) 0x2003, (char) 0x2004, (char) 0x2005,
183                                                                                                                                                           (char) 0x2006, (char) 0x2007, (char) 0x2008, (char) 0x2009, (char) 0x200A, (char) 0x200B, (char) 0x3000, (char) 0xFEFF };
184
185                 public String Trim(params char[] chars) {
186                         if (null == chars || chars.Length == 0)
187                                 chars = WhiteChars;
188
189                         return InternalTrim(chars, 0);
190                 }
191
192                 public String TrimStart(params char[] chars) {
193                         if (null == chars || chars.Length == 0)
194                                 chars = WhiteChars;
195
196                         return InternalTrim(chars, 1);
197                 }
198
199                 public String TrimEnd(params char[] chars) {
200                         if (null == chars || chars.Length == 0)
201                                 chars = WhiteChars;
202
203                         return InternalTrim(chars, 2);
204                 }
205
206                 public static int Compare(String s1, String s2) {
207                         return Compare(s1, s2, false);
208                 }
209
210                 public static int Compare(String s1, String s2, bool inCase) {
211                         if (null == s1) {
212                                 if (null == s2)
213                                         return 0;
214                                 else
215                                         return -1;
216                         } else if (null == s2)
217                                 return 1;
218
219                         return InternalCompare(s1, 0, s2, 0, Math.Max(s1.length, s2.length), inCase);
220                 }
221                 
222                 [MonoTODO()]
223                 public static int Compare(String s1, String s2, bool inCase, CultureInfo culture) {
224                         return Compare(s1, s2, inCase);
225                 }
226
227                 public static int Compare(String s1, int i1, String s2, int i2, int length) {
228                         return Compare(s1, i1, s2, i2, length, false);
229                 }
230
231                 public static int Compare(String s1, int i1, String s2, int i2, int length, bool inCase) {
232                         if (null == s1) {
233                                 if (null == s2)
234                                         return 0;
235                                 else
236                                         return -1;
237                         } else if (null == s2)
238                                 return 1;
239
240                         if (length < 0 || i1 < 0 || i2 < 0)
241                                 throw new ArgumentOutOfRangeException ();
242
243                         if (i1 > s1.length || i2 > s2.length)
244                                 throw new ArgumentOutOfRangeException ();
245
246                         if (length == 0)
247                                 return 0;
248
249                         return InternalCompare(s1, i1, s2, i2, length, inCase);
250                 }
251
252                 [MonoTODO()]
253                 public static int Compare(String s1, int i1, String s2, int i2, int length, bool inCase, CultureInfo culture) {
254                         return Compare(s1, i1, s2, i2, length, inCase);
255                 }
256
257                 public int CompareTo(Object value) {
258                         if (null == value)
259                                 return 1;
260             
261                         if (!(value is String))
262                                 throw new ArgumentException();
263
264                         return String.Compare(this, (String) value, false);
265                 }
266
267                 public int CompareTo(String str) {
268                         if (null == str)
269                                 return 1;
270
271                         return Compare(this, str, false);
272                 }
273
274                 public static int CompareOrdinal(String s1, String s2) {
275                         if (null == s1 || null == s2) {
276                                 if ((Object)s1 == (Object) s2) {
277                                         return 0;
278                                 }
279
280                                 return (s1 == null) ? -1 : 1;
281                         }
282
283                         return InternalCompare(s1, 0, s2, 0, Math.Max(s1.length, s2.length), false);
284                 }
285
286                 public static int CompareOrdinal(String s1, int i1, String s2, int i2, int length) {
287                         if (null == s1 || null == s2) {
288                                 if ((Object)s1 == (Object) s2) {
289                                         return 0;
290                                 }
291
292                                 return (s1 == null) ? -1 : 1;
293                         }
294
295                         if (i1 < 0 || i2 < 0 || length < 0)
296                                 throw new ArgumentOutOfRangeException ();
297
298                         if (i1 > s1.length || i2 > s2.length)
299                                 throw new ArgumentOutOfRangeException ();
300
301                         return InternalCompare(s1, i1, s2, i2, length, false);
302                 }
303
304                 public bool EndsWith(String value) {
305                         if (value.length > this.length) {
306                                 return false;
307                         }
308
309                         return (0 == Compare(this, length - value.length, value, 0, value.length));
310                 }
311         
312                 public int IndexOfAny(char [] arr) {
313                         if (null == arr)
314                                 throw new ArgumentNullException();
315
316                         return InternalIndexOfAny(arr, 0, this.length);
317                 }
318
319                 public int IndexOfAny(char [] arr, int sindex) {
320                         return InternalIndexOfAny(arr, sindex, this.length - sindex);
321                 }
322
323                 public int IndexOfAny(char [] arr, int sindex, int count) {
324                         return InternalIndexOfAny(arr, sindex, count);
325                 }
326
327                 public int IndexOf(char value) {
328                         return InternalIndexOf(value, 0, this.length);
329                 }
330
331                 public int IndexOf(String value) {
332                         return IndexOf(value, 0, this.length);
333                 }
334
335                 public int IndexOf(char value, int sindex) {
336                         if (sindex < 0 || sindex >= this.length) {
337                                 Console.WriteLine("value={0} sindex={0}\n", value, sindex);
338                                 throw new ArgumentOutOfRangeException();
339                         }
340
341                         return InternalIndexOf(value, sindex, this.length - sindex);
342                 }
343
344                 public int IndexOf(String value, int sindex) {
345                         return IndexOf(value, sindex, this.length - sindex);
346                 }
347
348                 public int IndexOf(char value, int sindex, int count) {
349                         if (sindex < 0 || count < 0 || sindex + count > this.length)
350                                 throw new ArgumentOutOfRangeException ();
351                         
352                         if (sindex == 0 && this.length == 0)
353                                 return -1;                      
354
355                         return InternalIndexOf(value, sindex, count);
356                 }
357                 
358                 public int IndexOf(String value, int sindex, int count) {
359                         if (null == value) 
360                                 throw new ArgumentNullException();
361
362                         if (sindex < 0 || count < 0 || sindex + count > this.length)
363                                 throw new ArgumentOutOfRangeException ();
364                         
365                         if (sindex == 0 && this.length == 0)
366                                 return -1;                      
367
368                         return InternalIndexOf(value, sindex, count);
369                 }
370
371                 public int LastIndexOfAny(char [] arr) {
372                         if (null == arr) 
373                                 throw new ArgumentNullException();
374
375                         return InternalLastIndexOfAny(arr, this.length - 1, this.length);
376                 }
377
378                 public int LastIndexOfAny(char [] arr, int sindex) {
379                         if (null == arr) 
380                                 throw new ArgumentNullException();
381
382                         if (sindex < 0 || sindex > this.length)
383                                 throw new ArgumentOutOfRangeException();
384
385                         if (this.length == 0)
386                                 return -1;
387
388                         return InternalLastIndexOfAny(arr, sindex, sindex + 1);
389                 }
390
391                 public int LastIndexOfAny(char [] arr, int sindex, int count) {
392                         if (null == arr) 
393                                 throw new ArgumentNullException();
394
395                         if (sindex < 0 || count < 0 || sindex > this.length || sindex - count < -1)
396                                 throw new ArgumentOutOfRangeException();
397
398                         if (this.length == 0)
399                                 return -1;
400
401                         return InternalLastIndexOfAny(arr, sindex, count);
402                 }
403
404                 public int LastIndexOf(char value) {
405                         return InternalLastIndexOf(value, this.length - 1, this.length);
406                 }
407
408                 public int LastIndexOf(String value) {
409                         if (null == value) 
410                                 throw new ArgumentNullException();
411
412                         return InternalLastIndexOf(value, this.length - 1, this.length);
413                 }
414
415                 public int LastIndexOf(char value, int sindex){
416                         return LastIndexOf(value, sindex, sindex + 1);
417                 }
418
419                 public int LastIndexOf(String value, int sindex) {
420                         return LastIndexOf(value, sindex, sindex + 1);
421                 }
422
423                 public int LastIndexOf(char value, int sindex, int count) {
424                         if (count < 0 || sindex < 0)
425                                 throw new ArgumentOutOfRangeException ();
426
427                         if (count > this.length || sindex > this.length)
428                                 throw new ArgumentOutOfRangeException ();
429
430                         if (sindex == 0 && this.length == 0)
431                                 return -1;
432
433                         return InternalLastIndexOf(value, sindex, count);
434                 }
435
436                 public int LastIndexOf(String value, int sindex, int count) {
437                         if (null == value) 
438                                 throw new ArgumentNullException();
439
440                         if (sindex < 0 || sindex > this.length)
441                                 throw new ArgumentOutOfRangeException ();
442
443                         if (count < 0 || count - sindex <= 0)
444                                 throw new ArgumentOutOfRangeException ();
445
446                         if (sindex == 0 && this.length == 0)
447                                 return -1;
448
449                         return InternalLastIndexOf(value, sindex, count);
450                 }
451
452                 public String PadLeft(int width) {
453                         return PadLeft(width, ' ');
454                 }
455
456                 public String PadLeft(int width, char chr) {
457                         if (width < 0)
458                                 throw new ArgumentException();
459
460                         if (width < this.length)
461                                 return String.Copy(this);
462
463                         return InternalPad(width, chr, false);
464                 }
465
466                 public String PadRight(int width) {
467                         return PadRight(width, ' ');
468                 }
469
470                 public String PadRight(int width, char chr) {
471                         if (width < 0)
472                                 throw new ArgumentException();
473
474                         if (width < this.length)
475                                 return String.Copy(this);
476
477                         return InternalPad(width, chr, true);
478                 }
479
480                 public bool StartsWith(String value) {
481                         if (this.length < value.length)
482                                 return false;
483
484                         return (0 == Compare(this, 0, value, 0 , value.length));
485                 }
486         
487     
488                 public String Replace (char oldChar, char newChar) {
489                         return InternalReplace(oldChar, newChar);
490                 }
491
492                 public String Replace(String oldValue, String newValue) {
493                         if (null == oldValue)
494                                 throw new ArgumentNullException();
495
496                         return InternalReplace(oldValue, newValue);
497                 }
498
499                 public String Remove(int sindex, int count) {
500                         if (sindex < 0 || count < 0 || sindex + count > this.length)
501                                 throw new ArgumentOutOfRangeException ();
502
503                         return InternalRemove(sindex, count);
504                 }
505
506                 public String ToLower() {
507                         return InternalToLower();
508                 }
509
510                 public String ToLower(CultureInfo culture) {
511                         throw new NotImplementedException();
512                 }
513
514                 public String ToUpper() {
515                         return InternalToUpper();
516                 }
517
518                 public String ToUpper(CultureInfo culture) {
519                         throw new NotImplementedException();
520                 }
521
522                 public override String ToString() {
523                         return this;
524                 }
525
526                 public String ToString(IFormatProvider provider) {
527                         return this;
528                 }
529
530                 public String Trim() {
531                         return Trim(null);
532                 }
533
534                 public static String Format(String format, Object arg0) {
535                         return Format(null, format, new Object[] {arg0});
536                 }
537
538                 public static String Format(String format, Object arg0, Object arg1) {
539                         return Format(null, format, new Object[] {arg0, arg1});
540                 }
541
542                 public static String Format(String format, Object arg0, Object arg1, Object arg2) {
543                         return Format(null, format, new Object[] {arg0, arg1, arg2});
544                 }
545
546                 public static string Format (string format, params object[] args) {
547                         return Format (null, format, args);
548                 }
549         
550                 public static string Format (IFormatProvider provider, string format, params object[] args) {
551                         if (format == null || args == null)
552                                 throw new ArgumentNullException ();
553                 
554                         StringBuilder result = new StringBuilder ();
555
556                         int ptr = 0;
557                         int start = ptr;
558                         while (ptr < format.length) {
559                                 char c = format[ptr ++];
560
561                                 if (c == '{') {
562                                         result.Append (format, start, ptr - start - 1);
563
564                                         // check for escaped open bracket
565
566                                         if (format[ptr] == '{') {
567                                                 start = ptr ++;
568                                                 continue;
569                                         }
570
571                                         // parse specifier
572                                 
573                                         int n, width;
574                                         bool left_align;
575                                         string arg_format;
576
577                                         ParseFormatSpecifier (format, ref ptr, out n, out width, out left_align, out arg_format);
578                                         if (n >= args.Length)
579                                                 throw new FormatException ("Index (zero based) must be greater than or equal to zero and less than the size of the argument list.");
580
581                                         // format argument
582
583                                         object arg = args[n];
584
585                                         string str;
586                                         if (arg == null)
587                                                 str = "";
588                                         else if (arg is IFormattable)
589                                                 str = ((IFormattable)arg).ToString (arg_format, provider);
590                                         else
591                                                 str = arg.ToString ();
592
593                                         // pad formatted string and append to result
594
595                                         if (width > str.length) {
596                                                 string pad = new String (' ', width - str.length);
597
598                                                 if (left_align) {
599                                                         result.Append (str);
600                                                         result.Append (pad);
601                                                 }
602                                                 else {
603                                                         result.Append (pad);
604                                                         result.Append (str);
605                                                 }
606                                         }
607                                         else
608                                                 result.Append (str);
609
610                                         start = ptr;
611                                 }
612                                 else if (c == '}' && format[ptr] == '}') {
613                                         result.Append (format, start, ptr - start - 1);
614                                         start = ptr ++;
615                                 }
616                         }
617
618                         if (start < format.length)
619                                 result.Append (format.Substring (start));
620
621                         return result.ToString ();
622                 }
623
624                 public static String Copy (String str) {
625                         if (str == null)
626                                 throw new ArgumentNullException ();
627
628                         int length = str.length;
629
630                         String tmp = InternalAllocateStr(length);
631                         InternalStrcpy(tmp, 0, str);
632                         return tmp;
633                 }
634
635                 public static String Concat(Object obj) {
636                         if (null == obj)
637                                 return String.Empty;
638
639                         return obj.ToString();
640                 }
641
642                 public static String Concat(Object obj1, Object obj2) {
643                         if (null == obj1)
644                                 obj1 = String.Empty;
645     
646                         if (null == obj2)
647                                 obj2 = String.Empty;
648
649                         return Concat(obj1.ToString(), obj2.ToString());
650                 }
651
652                 public static String Concat(Object obj1, Object obj2, Object obj3) {
653                         if (null == obj1)
654                                 obj1 = String.Empty;
655     
656                         if (null == obj2)
657                                 obj1 = String.Empty;
658     
659                         if (null == obj3)
660                                 obj1 = String.Empty;
661     
662                         return Concat(obj1.ToString(), obj2.ToString(), obj3.ToString());
663                 }
664
665                 [CLSCompliant(false)]
666                 public static String Concat(Object arg0, Object arg1, Object arg2, Object arg3, __arglist)  {
667                         throw new NotImplementedException();
668                 }
669
670                 public static String Concat(String s1, String s2) {
671                         if (null == s1) {
672                                 if (null == s2) { return String.Empty; }
673                                 return s2;
674                         }
675
676                         if (null == s2) { return s1; }
677
678                         String tmp = InternalAllocateStr(s1.length + s2.length);
679             
680                         InternalStrcpy(tmp, 0, s1);
681                         InternalStrcpy(tmp, s1.length, s2);
682             
683                         return tmp;
684                 }
685
686                 public static String Concat(String s1, String s2, String s3) {
687                         if (null == s1 && null == s2 && null == s3) {
688                                 return String.Empty;
689                         }
690
691                         if (null == s1) { s1 = String.Empty; }
692                         if (null == s2) { s2 = String.Empty; }
693                         if (null == s3) { s3 = String.Empty; }
694
695                         String tmp = InternalAllocateStr(s1.length + s2.length + s3.length);
696
697                         InternalStrcpy(tmp, 0, s1);
698                         InternalStrcpy(tmp, s1.length, s2);
699                         InternalStrcpy(tmp, s1.length + s2.length, s3);
700
701                         return tmp;
702                 }
703
704                 public static String Concat(String s1, String s2, String s3, String s4) {
705                         if (null == s1 && null == s2 && null == s3 && null == s4) {
706                                 return String.Empty;
707                         }
708
709                         if (null == s1) { s1 = String.Empty; }
710                         if (null == s2) { s2 = String.Empty; }
711                         if (null == s3) { s3 = String.Empty; }
712                         if (null == s4) { s4 = String.Empty; }
713
714                         String tmp = InternalAllocateStr(s1.length + s2.length + s3.length + s4.length);
715
716                         InternalStrcpy(tmp, 0, s1);
717                         InternalStrcpy(tmp, s1.length, s2);
718                         InternalStrcpy(tmp, s1.length + s2.length, s3);
719                         InternalStrcpy(tmp, s1.length + s2.length + s3.length, s4);
720
721                         return tmp;
722                 }
723
724                 public static String Concat(params Object[] args) {
725                         string [] strings;
726                         int len, i, currentpos;
727
728                         if (null == args)
729                                 throw new ArgumentNullException ();
730
731                         strings = new string [args.Length];
732                         len = 0;
733                         i = 0;
734                         foreach (object arg in args) {
735                                 /* use Empty for each null argument */
736                                 if (arg == null)
737                                         strings[i] = String.Empty;
738                                 else
739                                         strings[i] = arg.ToString ();
740                                 len += strings[i].length;
741                                 i++;
742                         }
743
744                         if (len == 0)
745                                 return String.Empty;
746
747                         currentpos = 0;
748
749                         String tmp = InternalAllocateStr(len);
750                         for (i = 0; i < strings.Length; i++) {
751                                 InternalStrcpy(tmp, currentpos, strings[i]);
752                                 currentpos += strings[i].length;
753                         }
754
755                         return tmp;
756                 }
757
758                 public static String Concat(params String[] values) {
759                         int len, i, currentpos;
760
761                         if (values == null)
762                                 throw new ArgumentNullException ();
763
764                         len = 0;
765                         foreach (string value in values)
766                                 len += value != null ? value.length : 0;
767
768                         if (len == 0)
769                                 return String.Empty;
770
771                         currentpos = 0;
772
773                         String tmp = InternalAllocateStr(len);
774                         for (i = 0; i < values.Length; i++) {
775                                 if (values[i] == null)
776                                         continue;
777
778                                 InternalStrcpy(tmp, currentpos, values[i]);
779                                 currentpos += values[i].length;
780                         }       
781         
782                         return tmp;
783                 }
784
785                 public String Insert(int sindex, String value) {
786                         if (null == value)
787                                 throw new ArgumentNullException();
788
789                         if (sindex < 0 || sindex > this.length)
790                                 throw new ArgumentOutOfRangeException();
791         
792                         return InternalInsert(sindex, value);
793                 }
794
795
796                 public static string Intern (string str) {
797                         if (null == str)
798                                 throw new ArgumentNullException ();
799
800                         return InternalIntern(str);
801                 }
802
803                 public static string IsInterned (string str) {
804                         if (null == str)
805                                 throw new ArgumentNullException();
806
807                         return InternalIsInterned(str);
808                 }
809         
810                 public static string Join (string separator, string [] value) {
811                         return Join(separator, value, 0, value.Length);
812                 }
813
814                 public static string Join(string separator, string[] value, int sindex, int count) {
815                         if (value == null)
816                                 throw new ArgumentNullException ();
817
818                         if (sindex + count > value.Length)
819                                 throw new ArgumentOutOfRangeException ();
820
821                         if (sindex == value.Length)
822                                 return String.Empty;
823
824                         return InternalJoin(separator, value, sindex, count);
825                 }
826
827                 bool IConvertible.ToBoolean (IFormatProvider provider) {
828                         return Convert.ToBoolean (this);
829                 }
830                 
831                 byte IConvertible.ToByte (IFormatProvider provider) {
832                         return Convert.ToByte (this);
833                 }
834                 
835                 char IConvertible.ToChar (IFormatProvider provider) {
836                         return Convert.ToChar (this);
837                 }
838
839                 DateTime IConvertible.ToDateTime (IFormatProvider provider) {
840                         return Convert.ToDateTime (this);
841                 }
842
843                 decimal IConvertible.ToDecimal (IFormatProvider provider) {
844                         return Convert.ToDecimal (this);
845                 }
846
847                 double IConvertible.ToDouble (IFormatProvider provider) {
848                         return Convert.ToDouble (this);
849                 }
850
851                 short IConvertible.ToInt16 (IFormatProvider provider) {
852                         return Convert.ToInt16 (this);
853                 }
854
855                 int IConvertible.ToInt32 (IFormatProvider provider) {
856                         return Convert.ToInt32 (this);
857                 }
858
859                 long IConvertible.ToInt64 (IFormatProvider provider) {
860                         return Convert.ToInt64 (this);
861                 }
862         
863                 [CLSCompliant(false)]
864                 sbyte IConvertible.ToSByte (IFormatProvider provider) {
865                         return Convert.ToSByte (this);
866                 }
867
868                 float IConvertible.ToSingle (IFormatProvider provider) {
869                         return Convert.ToSingle (this);
870                 }
871                 string IConvertible.ToString (IFormatProvider format) {
872                         return this;
873                 }
874
875                 object IConvertible.ToType (Type conversionType, IFormatProvider provider) {
876                         return Convert.ToType (this, conversionType,  provider);
877                 }
878
879                 [CLSCompliant(false)]
880                 ushort IConvertible.ToUInt16 (IFormatProvider provider) {
881                         return Convert.ToUInt16 (this);
882                 }
883
884                 [CLSCompliant(false)]
885                 uint IConvertible.ToUInt32 (IFormatProvider provider) {
886                         return Convert.ToUInt32 (this);
887                 }
888
889                 [CLSCompliant(false)]
890                 ulong IConvertible.ToUInt64 (IFormatProvider provider) {
891                         return Convert.ToUInt64 (this);
892                 }
893
894                 TypeCode IConvertible.GetTypeCode () {
895                         return TypeCode.String;
896                 }
897
898                 public int Length {
899                         get {
900                                 return length;
901                         }
902                 }
903
904                 public CharEnumerator GetEnumerator () {
905                         return new CharEnumerator (this);
906                 }
907                 
908                 IEnumerator IEnumerable.GetEnumerator () {
909                         return new CharEnumerator (this);
910                 }
911
912                 private static void ParseFormatSpecifier (string str, ref int ptr, out int n, out int width, out bool left_align, out string format) {
913                         // parses format specifier of form:
914                         //   N,[[-]M][:F]}
915                         //
916                         // where:
917
918                         try {
919                                 // N = argument number (non-negative integer)
920                         
921                                 n = ParseDecimal (str, ref ptr);
922                                 if (n < 0)
923                                         throw new FormatException ("Input string was not in correct format.");
924                                 
925                                 // M = width (non-negative integer)
926
927                                 if (str[ptr] == ',') {
928                                         left_align = (str[++ ptr] == '-');
929                                         if (left_align)
930                                                 ++ ptr;
931
932                                         width = ParseDecimal (str, ref ptr);
933                                         if (width < 0)
934                                                 throw new FormatException ("Input string was not in correct format.");
935                                 }
936                                 else {
937                                         width = 0;
938                                         left_align = false;
939                                 }
940
941                                 // F = argument format (string)
942
943                                 if (str[ptr] == ':') {
944                                         int start = ++ ptr;
945                                         while (str[ptr] != '}')
946                                                 ++ ptr;
947
948                                         format = str.Substring (start, ptr - start);
949                                 }
950                                 else
951                                         format = null;
952
953                                 if (str[ptr ++] != '}')
954                                         throw new FormatException ("Input string was not in correct format.");
955                         }
956                         catch (IndexOutOfRangeException) {
957                                 throw new FormatException ("Input string was not in correct format.");
958                         }
959                 }
960
961                 private static int ParseDecimal (string str, ref int ptr) {
962                         int p = ptr;
963                         int n = 0;
964                         while (true) {
965                                 char c = str[p];
966                                 if (c < '0' || '9' < c)
967                                         break;
968
969                                 n = n * 10 + c - '0';
970                                 ++ p;
971                         }
972
973                         if (p == ptr)
974                                 return -1;
975                         
976                         ptr = p;
977                         return n;
978                 }
979                 
980                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
981                 private extern static string InternalJoin(string separator, string[] value, int sindex, int count);
982                 
983                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
984                 private extern String InternalInsert(int sindex, String value);
985
986                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
987                 private extern String InternalReplace(char oldChar, char newChar);
988
989                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
990                 private extern String InternalReplace(String oldValue, String newValue);
991     
992                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
993                 private extern String InternalRemove(int sindex, int count);
994                 
995                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
996                 private extern void InternalCopyTo(int sindex, char[] dest, int dindex, int count);
997
998                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
999                 private extern String[] InternalSplit(char[] separator, int count);
1000
1001                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1002                 private extern String InternalTrim(char[] chars, int typ);
1003
1004                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1005                 private extern int InternalIndexOf(char value, int sindex, int count);
1006
1007                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1008                 private extern int InternalIndexOf(string value, int sindex, int count);
1009
1010                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1011                 private extern int InternalIndexOfAny(char [] arr, int sindex, int count);
1012
1013                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1014                 private extern int InternalLastIndexOf(char value, int sindex, int count);
1015
1016                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1017                 private extern int InternalLastIndexOf(String value, int sindex, int count);
1018
1019                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1020                 private extern int InternalLastIndexOfAny(char [] anyOf, int sindex, int count);
1021
1022                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1023                 private extern String InternalPad(int width, char chr, bool right);
1024
1025                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1026                 private extern String InternalToLower();
1027
1028                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1029                 private extern String InternalToUpper();
1030
1031                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1032                 private extern static String InternalAllocateStr(int length);
1033
1034                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1035                 private extern static void InternalStrcpy(String dest, int destPos, String src);
1036
1037                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1038                 private extern static void InternalStrcpy(String dest, int destPos, String src, int startPos, int count);
1039
1040                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1041                 private extern static string InternalIntern(string str);
1042
1043                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1044                 private extern static string InternalIsInterned(string str);
1045
1046                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1047                 private extern static int InternalCompare(String s1, int i1, String s2, int i2, int length, bool inCase);
1048         }
1049 }