| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634 |
- // -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- //
- // System.String.cs
- //
- // Author:
- // Jeffrey Stedfast ([email protected])
- //
- // (C) 2001 Ximian, Inc. http://www.ximian.com
- //
- // FIXME: from what I gather from msdn, when a function is to return an empty string
- // we should be returning this.Empty - some methods do this and others don't.
- // FIXME: I didn't realise until later that `string' has a .Length method and so
- // I am missing some proper bounds-checking in some methods. Find these
- // instances and throw the ArgumentOutOfBoundsException at the programmer.
- // I like pelting programmers with ArgumentOutOfBoundsException's :-)
- // FIXME: The ToLower(), ToUpper(), and Compare(..., bool ignoreCase) methods
- // need to be made unicode aware.
- // FIXME: when you have a char carr[], does carr.Length include the terminating null char?
- using System;
- using System.Text;
- using System.Collections;
- using System.Globalization;
- namespace System {
- public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable {
- public static readonly string Empty = "";
- private char[] c_str;
- private int length;
- // Constructors
- unsafe public String (char *value)
- {
- int i;
- // FIXME: can I do value.Length here?
- if (value == null) {
- this.length = 0;
- } else {
- for (i = 0; *(value + i) != '\0'; i++);
- this.length = i;
- }
- this.c_str = new char [this.length + 1];
- for (i = 0; i < this.length; i++)
- this.c_str[i] = *(value + i);
- this.c_str[i] = '\0';
- }
- public String (char[] value)
- {
- int i;
- // FIXME: value.Length includes the terminating null char?
- this.length = value != null ? strlen (value): 0;
- this.c_str = new char [this.length + 1];
- for (i = 0; i < this.length; i++)
- this.c_str[i] = value[i];
- this.c_str[i] = '\0';
- }
- unsafe public String (sbyte *value)
- {
- // FIXME: consider unicode?
- int i;
- // FIXME: can I do value.Length here? */
- if (value == null) {
- this.length = 0;
- } else {
- for (i = 0; *(value + i) != '\0'; i++);
- this.length = i;
- }
- this.c_str = new char [this.length + 1];
- for (i = 0; i < this.length; i++)
- this.c_str[i] = (char) *(value + i);
- this.c_str[i] = '\0';
- }
- public String (char c, int count)
- {
- int i;
- this.length = count;
- this.c_str = new char [count + 1];
- for (i = 0; i < count; i++)
- this.c_str[i] = c;
- this.c_str[i] = '\0';
- }
- unsafe public String (char *value, int startIndex, int length)
- {
- int i;
- if (value == null && startIndex != 0 && length != 0)
- throw new ArgumentNullException ();
- if (startIndex < 0 || length < 0)
- throw new ArgumentOutOfRangeException ();
- this.length = length;
- this.c_str = new char [length + 1];
- for (i = 0; i < length; i++)
- this.c_str[i] = *(value + startIndex + i);
- this.c_str[i] = '\0';
- }
- public String (char[] value, int startIndex, int length)
- {
- int i;
- if (value == null && startIndex != 0 && length != 0)
- throw new ArgumentNullException ();
- if (startIndex < 0 || length < 0)
- throw new ArgumentOutOfRangeException ();
- this.length = length;
- this.c_str = new char [length + 1];
- for (i = 0; i < length; i++)
- this.c_str[i] = value[startIndex + i];
- this.c_str[i] = '\0';
- }
- unsafe public String (sbyte *value, int startIndex, int length)
- {
- // FIXME: consider unicode?
- int i;
- if (value == null && startIndex != 0 && length != 0)
- throw new ArgumentNullException ();
- if (startIndex < 0 || length < 0)
- throw new ArgumentOutOfRangeException ();
- this.length = length;
- this.c_str = new char [length + 1];
- for (i = 0; i < length; i++)
- this.c_str[i] = (char) *(value + startIndex + i);
- this.c_str[i] = '\0';
- }
- unsafe public String (sbyte *value, int startIndex, int length, Encoding enc)
- {
- // FIXME: implement me
- }
- ~String ()
- {
- // FIXME: is there anything we need to do here?
- /*base.Finalize ();*/
- }
- // Properties
- public int Length {
- get {
- return this.length;
- }
- }
- // FIXME: is this correct syntax??
- public char this [int index] {
- get {
- if (index > this.length)
- throw new ArgumentOutOfRangeException ();
- return this.c_str[index];
- }
- }
- // Private helper methods
- private static int strlen (char[] str)
- {
- // FIXME: if str.Length includes terminating null char, then return (str.Length - 1)
- return str.Length;
- }
- private static char tolowerordinal (char c)
- {
- // FIXME: implement me
- return c;
- }
- private static bool is_lwsp (char c)
- {
- /* this comes from the msdn docs for String.Trim() */
- if ((c >= '\x9' && c <= '\xD') || c == '\x20' || c == '\xA0' ||
- (c >= '\x2000' && c <= '\x200B') || c == '\x3000' || c == '\xFEFF')
- return true;
- else
- return false;
- }
- private static int BoyerMoore (char[] haystack, string needle, int startIndex, int count)
- {
- /* (hopefully) Unicode-safe Boyer-Moore implementation */
- int[] skiptable = new int[65536]; /* our unicode-safe skip-table */
- int h, n, he, ne, hc, nc, i;
- if (haystack == null || needle == null)
- throw new ArgumentNullException ();
- /* if the search buffer is shorter than the pattern buffer, we can't match */
- if (count < needle.Length)
- return -1;
- /* return an instant match if the pattern is 0-length */
- if (needle.Length == 0)
- return startIndex;
- /* set a pointer at the end of each string */
- ne = needle.Length - 1; /* position of char before '\0' */
- he = startIndex + count; /* position of last valid char */
- /* init the skip table with the pattern length */
- for (i = 0; i < 65536; i++)
- skiptable[i] = needle.Length;
- /* set the skip value for the chars that *do* appear in the
- * pattern buffer (needle) to the distance from the index to
- * the end of the pattern buffer. */
- for (nc = 0; nc < ne; nc++)
- skiptable[(int) needle[nc]] = ne - nc;
- h = startIndex;
- while (count >= needle.Length) {
- hc = h + needle.Length - 1; /* set the haystack compare pointer */
- nc = ne; /* set the needle compare pointer */
- /* work our way backwards until they don't match */
- for (i = 0; nc > 0; nc--, hc--, i++)
- if (needle[nc] != haystack[hc])
- break;
- if (needle[nc] != haystack[hc]) {
- n = skiptable[(int) haystack[hc]] - i;
- h += n;
- count -= n;
- } else
- return h;
- }
- return -1;
- }
- // Methods
- public object Clone ()
- {
- // FIXME: implement me
- return null;
- }
- public static int Compare (string strA, string strB)
- {
- int i;
- /* Does this remind anyone of the nautilus string.h wrappers? ;-) */
- if (strA == null) {
- if (strB == null)
- return 0;
- else
- return -1;
- } else if (strB == null)
- return 1;
- for (i = 0; strA[i] == strB[i] && strA[i] != '\0'; i++);
- return ((int) (strA[i] - strB[i]));
- }
- public static int Compare (string strA, string strB, bool ignoreCase)
- {
- int i;
- if (!ignoreCase)
- return Compare (strA, strB);
- /*
- * And here I thought Eazel developers were on crack...
- * if a string is null it should pelt the programmer with
- * ArgumentNullExceptions, damnit!
- */
- if (strA == null) {
- if (strB == null)
- return 0;
- else
- return -1;
- } else if (strB == null)
- return 1;
- for (i = 0; strA[i] != '\0' && strB[i] != '\0'; i++) {
- if (Char.ToLower (strA[i]) != Char.ToLower (strB[i]))
- break;
- }
- return ((int) (strA[i] - strB[i]));
- }
- public static int Compare (string strA, string strB, bool ignoreCase, CultureInfo culture)
- {
- // FIXME: implement me
- return 0;
- }
- public static int Compare (string strA, int indexA, string strB, int indexB, int length)
- {
- int i;
- if (length < 0 || indexA < 0 || indexB < 0)
- throw new ArgumentOutOfRangeException ();
- if (indexA > strA.Length || indexB > strB.Length)
- throw new ArgumentOutOfRangeException ();
- /* And again with the ("" > null) logic... lord have mercy! */
- if (strA == null) {
- if (strB == null)
- return 0;
- else
- return -1;
- } else if (strB == null)
- return 1;
- for (i = 0; i < length - 1; i++) {
- if (strA[indexA + i] != strB[indexB + i])
- break;
- }
- return ((int) (strA[indexA + i] - strB[indexB + i]));
- }
- public static int Compare (string strA, int indexA, string strB, int indexB,
- int length, bool ignoreCase)
- {
- int i;
- if (!ignoreCase)
- return Compare (strA, indexA, strB, indexB, length);
- if (length < 0 || indexA < 0 || indexB < 0)
- throw new ArgumentOutOfRangeException ();
- if (indexA > strA.Length || indexB > strB.Length)
- throw new ArgumentOutOfRangeException ();
- /* When will the hurting stop!?!? */
- if (strA == null) {
- if (strB == null)
- return 0;
- else
- return -1;
- } else if (strB == null)
- return 1;
- for (i = 0; i < length - 1; i++) {
- if (Char.ToLower (strA[indexA + i]) != Char.ToLower (strB[indexB + i]))
- break;
- }
- return ((int) (strA[indexA + i] - strB[indexB + i]));
- }
- public static int Compare (string strA, int indexA, string strB, int indexB,
- int length, bool ignoreCase, CultureInfo culture)
- {
- if (culture == null)
- throw new ArgumentNullException ();
- if (length < 0 || indexA < 0 || indexB < 0)
- throw new ArgumentOutOfRangeException ();
- if (indexA > strA.Length || indexB > strB.Length)
- throw new ArgumentOutOfRangeException ();
- /* I can't take it anymore! */
- if (strA == null) {
- if (strB == null)
- return 0;
- else
- return -1;
- } else if (strB == null)
- return 1;
- // FIXME: implement me
- return 0;
- }
- public static int CompareOrdinal (string strA, string strB)
- {
- int i;
- /* Please God, make it stop! */
- if (strA == null) {
- if (strB == null)
- return 0;
- else
- return -1;
- } else if (strB == null)
- return 1;
- for (i = 0; strA[i] != '\0'; i++) {
- char cA, cB;
- cA = tolowerordinal (strA[i]);
- cB = tolowerordinal (strB[i]);
- if (cA != cB)
- break;
- }
- return ((int) (strA[i] - strB[i]));
- }
- public static int CompareOrdinal (string strA, int indexA, string strB, int indexB,
- int length)
- {
- int i;
- if (length < 0 || indexA < 0 || indexB < 0)
- throw new ArgumentOutOfRangeException ();
- /* Nooooooooo!! */
- if (strA == null) {
- if (strB == null)
- return 0;
- else
- return -1;
- } else if (strB == null)
- return 1;
- for (i = 0; i < length; i++) {
- char cA, cB;
- cA = tolowerordinal (strA[indexA + i]);
- cB = tolowerordinal (strB[indexB + i]);
- if (cA != cB)
- break;
- }
- return ((int) (strA[indexA + i] - strB[indexB + i]));
- }
- public int CompareTo (object obj)
- {
- return Compare (this, obj == null ? null : obj.ToString ());
- }
- public int CompareTo (string str)
- {
- return Compare (this, str);
- }
- public static string Concat (object arg)
- {
- return arg != null ? arg.ToString () : String.Empty;
- }
- public static string Concat (params object[] args)
- {
- string[] strings;
- char[] str;
- int len, i;
- if (args == null)
- throw new ArgumentNullException ();
- strings = new string [args.Length];
- len = 0;
- i = 0;
- foreach (object arg in args) {
- /* use Empty for each null argument */
- if (arg == null)
- strings[i] = String.Empty;
- else
- strings[i] = arg.ToString ();
- len += strings[i].Length;
- i++;
- }
- if (len == 0)
- return String.Empty;
- str = new char [len + 1];
- i = 0;
- for (int j = 0; j < strings.Length; j++)
- for (int k = 0; k < strings[j].Length; k++)
- str[i++] = strings[j][k];
- str[i] = '\0';
- return new String (str);
- }
- public static string Concat (params string[] values)
- {
- int len, i;
- char[] str;
- if (values == null)
- throw new ArgumentNullException ();
- len = 0;
- foreach (string value in values)
- len += value != null ? value.Length : 0;
- if (len == 0)
- return String.Empty;
- str = new char [len + 1];
- i = 0;
- foreach (string value in values) {
- if (value == null)
- continue;
- for (int j = 0; j < value.Length; j++)
- str[i++] = value[j];
- }
- str[i] = '\0';
- return new String (str);
- }
- public static string Concat (object arg0, object arg1)
- {
- string str0 = arg0 != null ? arg0.ToString () : String.Empty;
- string str1 = arg1 != null ? arg1.ToString () : String.Empty;
- return Concat (str0, str1);
- }
- public static string Concat (string str0, string str1)
- {
- char[] concat;
- int i, j, len;
- if (str0 == null)
- str0 = String.Empty;
- if (str1 == null)
- str1 = String.Empty;
- len = str0.Length + str1.Length;
- if (len == 0)
- return String.Empty;
- concat = new char [len + 1];
- for (i = 0; i < str0.Length; i++)
- concat[i] = str0[i];
- for (j = 0 ; j < str1.Length; j++)
- concat[i + j] = str1[j];
- concat[len] = '\0';
- return new String (concat);
- }
- public static string Concat (object arg0, object arg1, object arg2)
- {
- string str0 = arg0 != null ? arg0.ToString () : String.Empty;
- string str1 = arg1 != null ? arg1.ToString () : String.Empty;
- string str2 = arg2 != null ? arg2.ToString () : String.Empty;
- return Concat (str0, str1, str2);
- }
- public static string Concat (string str0, string str1, string str2)
- {
- char[] concat;
- int i, j, k, len;
- if (str0 == null)
- str0 = String.Empty;
- if (str1 == null)
- str1 = String.Empty;
- if (str2 == null)
- str2 = String.Empty;
- len = str0.Length + str1.Length + str2.Length;
- if (len == 0)
- return String.Empty;
- concat = new char [len + 1];
- for (i = 0; i < str0.Length; i++)
- concat[i] = str0[i];
- for (j = 0; j < str1.Length; j++)
- concat[i + j] = str1[j];
- for (k = 0; k < str2.Length; k++)
- concat[i + j + k] = str2[k];
- concat[len] = '\0';
- return new String (concat);
- }
- public static string Concat (string str0, string str1, string str2, string str3)
- {
- char[] concat;
- int i, j, k, l, len;
- if (str0 == null)
- str0 = String.Empty;
- if (str1 == null)
- str1 = String.Empty;
- if (str2 == null)
- str2 = String.Empty;
- if (str3 == null)
- str3 = String.Empty;
- len = str0.Length + str1.Length + str2.Length + str3.Length;
- if (len == 0)
- return String.Empty;
- concat = new char [len + 1];
- for (i = 0; i < str0.Length; i++)
- concat[i] = str0[i];
- for (j = 0; j < str1.Length; j++)
- concat[i + j] = str1[j];
- for (k = 0; k < str2.Length; k++)
- concat[i + j + k] = str2[k];
- for (l = 0; l < str3.Length; l++)
- concat[i + j + k + l] = str3[l];
- concat[len] = '\0';
- return new String (concat);
- }
- public static string Copy (string str)
- {
- // FIXME: how do I *copy* a string if I can only have 1 of each?
- if (str == null)
- throw new ArgumentNullException ();
- return str;
- }
- public void CopyTo (int sourceIndex, char[] destination, int destinationIndex, int count)
- {
- // LAMESPEC: should I null-terminate?
- int i;
- if (destination == null)
- throw new ArgumentNullException ();
- if (sourceIndex < 0 || destinationIndex < 0 || count < 0)
- throw new ArgumentOutOfRangeException ();
- if (sourceIndex + count > this.length)
- throw new ArgumentOutOfRangeException ();
- if (destinationIndex + count > destination.Length)
- throw new ArgumentOutOfRangeException ();
- for (i = 0; i < count; i++)
- destination[destinationIndex + i] = this.c_str[sourceIndex + i];
- }
- public bool EndsWith (string value)
- {
- bool endswith = true;
- int start, i;
- if (value == null)
- throw new ArgumentNullException ();
- start = this.length - value.Length;
- if (start < 0)
- return false;
- for (i = start; i < this.length && endswith; i++)
- endswith = this.c_str[i] == value[i - start];
- return endswith;
- }
- public override bool Equals (object obj)
- {
- if (!(obj is String))
- return false;
- return this == (String) obj;
- }
- public bool Equals (string value)
- {
- return this == value;
- }
- public static bool Equals (string a, string b)
- {
- return a == b;
- }
- public static string Format (string format, object arg0)
- {
- // FIXME: implement me
- return null;
- }
- public static string Format (string format, params object[] args)
- {
- // FIXME: implement me
- return null;
- }
- public static string Format (IFormatProvider provider, string format, params object[] args)
- {
- // FIXME: implement me
- return null;
- }
- public static string Format (string format, object arg0, object arg1)
- {
- // FIXME: implement me
- return null;
- }
- public static string Format (string format, object arg0, object arg1, object arg2)
- {
- // FIXME: implement me
- return null;
- }
- //public CharEnumerator GetEnumerator ()
- public IEnumerator GetEnumerator ()
- {
- // FIXME: implement me
- return null;
- }
- public override int GetHashCode ()
- {
- // FIXME: implement me
- return 0;
- }
- public new Type GetType ()
- {
- // FIXME: implement me
- return null;
- }
- public TypeCode GetTypeCode ()
- {
- // FIXME: implement me
- return 0;
- }
- public int IndexOf (char value)
- {
- return IndexOf (value, 0, this.length);
- }
- public int IndexOf (string value)
- {
- return IndexOf (value, 0, this.length);
- }
- public int IndexOf (char value, int startIndex)
- {
- return IndexOf (value, startIndex, this.length - startIndex);
- }
- public int IndexOf (string value, int startIndex)
- {
- return IndexOf (value, startIndex, this.length - startIndex);
- }
- public int IndexOf (char value, int startIndex, int count)
- {
- int i;
- if (startIndex < 0 || count < 0 || startIndex + count > this.length)
- throw new ArgumentOutOfRangeException ();
- for (i = startIndex; i - startIndex < count; i++)
- if (this.c_str[i] == value)
- return i;
- return -1;
- }
- public int IndexOf (string value, int startIndex, int count)
- {
- int i;
- if (value == null)
- throw new ArgumentNullException ();
- if (startIndex < 0 || count < 0 || startIndex + count > this.length)
- throw new ArgumentOutOfRangeException ();
- return BoyerMoore (this.c_str, value, startIndex, count);
- #if XXX
- for (i = startIndex; i - startIndex + value.Length <= count; ) {
- if (this.c_str[i] == value[0]) {
- bool equal = true;
- int j, nexti = 0;
- for (j = 1; equal && value[j] != '\0'; j++) {
- equal = this.c_str[i + j] == value[j];
- if (this.c_str[i + j] == value[0] && nexti == 0)
- nexti = i + j;
- }
- if (equal)
- return i;
- if (nexti != 0)
- i = nexti;
- else
- i += j;
- } else
- i++;
- }
- return -1;
- #endif
- }
- public int IndexOfAny (char[] values)
- {
- return IndexOfAny (values, 0, this.length);
- }
- public int IndexOfAny (char[] values, int startIndex)
- {
- return IndexOfAny (values, startIndex, this.length - startIndex);
- }
- public int IndexOfAny (char[] values, int startIndex, int count)
- {
- if (values == null)
- throw new ArgumentNullException ();
- if (startIndex < 0 || count < 0 || startIndex + count > this.length)
- throw new ArgumentOutOfRangeException ();
- for (int i = startIndex; i < startIndex + count; i++) {
- for (int j = 0; j < strlen (values); j++) {
- if (this.c_str[i] == values[j])
- return i;
- }
- }
- return -1;
- }
- public string Insert (int startIndex, string value)
- {
- char[] str;
- int i, j;
- if (value == null)
- throw new ArgumentNullException ();
- if (startIndex < 0 || startIndex > this.length)
- throw new ArgumentOutOfRangeException ();
- str = new char [value.Length + this.length + 1];
- for (i = 0; i < startIndex; i++)
- str[i] = this.c_str[i];
- for (j = 0; j < value.Length; j++)
- str[i + j] = value[j];
- for ( ; i < this.length; i++)
- str[i + j] = this.c_str[i];
- str[i + j] = '\0';
- return new String (str);
- }
- public static string Intern (string str)
- {
- if (str == null)
- throw new ArgumentNullException ();
- // FIXME: implement me
- return null;
- }
- public static string IsInterned (string str)
- {
- if (str == null)
- throw new ArgumentNullException ();
- // FIXME: implement me
- return null;
- }
- public static string Join (string separator, string[] value)
- {
- return Join (separator, value, 0, value.Length);
- }
- public static string Join (string separator, string[] value, int startIndex, int count)
- {
- // LAMESPEC: msdn doesn't specify what happens when separator is null
- int len, i, j, used;
- char[] str;
- if (separator == null || value == null)
- throw new ArgumentNullException ();
- if (startIndex + count > value.Length)
- throw new ArgumentOutOfRangeException ();
- len = 0;
- for (i = startIndex, used = 0; used < count; i++, used++) {
- if (i != startIndex)
- len += separator.Length;
- len += value[i].Length;
- }
- // We have no elements to join?
- if (i == startIndex)
- return String.Empty;
- str = new char [len + 1];
- for (i = 0; i < value[startIndex].Length; i++)
- str[i] = value[startIndex][i];
- used = 1;
- for (j = startIndex + 1; used < count; j++, used++) {
- int k;
- for (k = 0; k < separator.Length; k++)
- str[i++] = separator[k];
- for (k = 0; k < value[j].Length; k++)
- str[i++] = value[j][k];
- }
- str[i] = '\0';
- return new String (str);
- }
- public int LastIndexOf (char value)
- {
- for (int i = this.length; i >= 0; i--) {
- if (this.c_str[i] == value)
- return i;
- }
- return -1;
- }
- public int LastIndexOf (string value)
- {
- return LastIndexOf (value, this.length, this.length);
- }
- public int LastIndexOf (char value, int startIndex)
- {
- if (startIndex < 0 || startIndex > this.length)
- throw new ArgumentOutOfRangeException ();
- for (int i = startIndex; i >= 0; i--) {
- if (this.c_str[i] == value)
- return i;
- }
- return -1;
- }
- public int LastIndexOf (string value, int startIndex)
- {
- return LastIndexOf (value, startIndex, this.length);
- }
- public int LastIndexOf (char value, int startIndex, int count)
- {
- if (startIndex < 0 || count < 0)
- throw new ArgumentOutOfRangeException ();
- if (startIndex > this.length || startIndex - count < 0)
- throw new ArgumentOutOfRangeException ();
- for (int i = startIndex; i >= startIndex - count; i--) {
- if (this.c_str[i] == value)
- return i;
- }
- return -1;
- }
- public int LastIndexOf (string value, int startIndex, int count)
- {
- // LAMESPEC: currently I'm using startIndex as the 0-position in the comparison,
- // but maybe it's the end-position in MS's implementation?
- // msdn is unclear on this point. I think this is correct though.
- int i, len;
- if (value == null)
- throw new ArgumentNullException ();
- if (startIndex < 0 || startIndex > this.length)
- throw new ArgumentOutOfRangeException ();
- if (count < 0 || startIndex - count < 0)
- throw new ArgumentOutOfRangeException ();
- if (value == String.Empty)
- return startIndex;
- if (startIndex + value.Length > this.length) {
- /* just a little optimization */
- int start;
- start = this.length - value.Length;
- count -= startIndex - start;
- startIndex = start;
- }
- // FIXME: use a reversed-unicode-safe-Boyer-Moore?
- len = value.Length - 1;
- for (i = startIndex; i >= startIndex - count; i--) {
- if (this.c_str[i + len] == value[len]) {
- bool equal = true;
- int j;
- for (j = len - 1; equal && j >= 0; j--)
- equal = this.c_str[i + j] == value[j];
- if (equal)
- return i;
- }
- }
- return -1;
- }
- public int LastIndexOfAny (char[] values)
- {
- return LastIndexOfAny (values, this.length, this.length);
- }
- public int LastIndexOfAny (char[] values, int startIndex)
- {
- return LastIndexOfAny (values, startIndex, startIndex);
- }
- public int LastIndexOfAny (char[] values, int startIndex, int count)
- {
- int i;
- if (values == null)
- throw new ArgumentNullException ();
- if (startIndex < 0 || count < 0 || startIndex - count < 0)
- throw new ArgumentOutOfRangeException ();
- for (i = startIndex; i >= startIndex - count; i--) {
- for (int j = 0; j < strlen (values); j++) {
- if (this.c_str[i] == values[j])
- return i;
- }
- }
- return -1;
- }
- public string PadLeft (int totalWidth)
- {
- return PadLeft (totalWidth, ' ');
- }
- public string PadLeft (int totalWidth, char padChar)
- {
- char[] str;
- int i, j;
- if (totalWidth < 0)
- throw new ArgumentException ();
- str = new char [totalWidth > this.length ? totalWidth : this.length + 1];
- for (i = 0; i < totalWidth - this.length; i++)
- str[i] = padChar;
- for (j = 0; j < this.length; i++, j++)
- str[i] = this.c_str[j];
- str[i] = '\0';
- return new String (str);
- }
- public string PadRight (int totalWidth)
- {
- return PadRight (totalWidth, ' ');
- }
- public string PadRight (int totalWidth, char padChar)
- {
- char[] str;
- int i;
- if (totalWidth < 0)
- throw new ArgumentException ();
- str = new char [totalWidth > this.length ? totalWidth : this.length + 1];
- for (i = 0; i < this.length; i++)
- str[i] = this.c_str[i];
- for ( ; i < str.Length; i++)
- str[i] = padChar;
- str[i] = '\0';
- return new String (str);
- }
- public string Remove (int startIndex, int count)
- {
- char[] str;
- int i, j, len;
- if (startIndex < 0 || count < 0 || startIndex + count > this.length)
- throw new ArgumentOutOfRangeException ();
- len = this.length - count;
- if (len == 0)
- return String.Empty;
- str = new char [len + 1];
- for (i = 0; i < startIndex; i++)
- str[i] = this.c_str[i];
- for (j = i + count; j < this.length; j++)
- str[i++] = this.c_str[j];
- str[i] = '\0';
- return new String (str);
- }
- public string Replace (char oldChar, char newChar)
- {
- char[] str;
- int i;
- str = new char [this.length + 1];
- for (i = 0; i < this.length; i++) {
- if (this.c_str[i] == oldChar)
- str[i] = newChar;
- else
- str[i] = this.c_str[i];
- }
- str[i] = '\0';
- return new String (str);
- }
- public string Replace (string oldValue, string newValue)
- {
- // LAMESPEC: msdn doesn't specify what to do if either args is null
- int index, len, i, j;
- char[] str;
- if (oldValue == null || newValue == null)
- throw new ArgumentNullException ();
- // Use IndexOf in case I later rewrite it to use Boyer-Moore
- index = IndexOf (oldValue, 0);
- if (index == -1) {
- // This is the easy one ;-)
- return Substring (0, this.length);
- }
- len = this.length - oldValue.Length + newValue.Length;
- if (len == 0)
- return String.Empty;
- str = new char [len + 1];
- for (i = 0; i < index; i++)
- str[i] = this.c_str[i];
- for (j = 0; j < newValue.Length; j++)
- str[i++] = newValue[j];
- for (j = index + oldValue.Length; j < this.length; j++)
- str[i++] = this.c_str[j];
- str[i] = '\0';
- return new String (str);
- }
- private int splitme (char[] separators, int startIndex)
- {
- /* this is basically a customized IndexOfAny() for the Split() methods */
- for (int i = startIndex; i < this.length; i++) {
- if (separators != null) {
- foreach (char sep in separators) {
- if (this.c_str[i] == sep)
- return i - startIndex;
- }
- } else if (is_lwsp (this.c_str[i])) {
- return i - startIndex;
- }
- }
- return -1;
- }
- public string[] Split (params char[] separator)
- {
- /**
- * split:
- * @separator: delimiting chars or null to split on whtspc
- *
- * Returns: 1. An array consisting of a single
- * element (@this) if none of the delimiting
- * chars appear in @this. 2. An array of
- * substrings which are delimited by one of
- * the separator chars. 3. An array of
- * substrings separated by whitespace if
- * @separator is null. The Empty string should
- * be returned wherever 2 delimiting chars are
- * adjacent.
- **/
- // FIXME: would using a Queue be better?
- string[] strings;
- ArrayList list;
- int index, len;
- list = new ArrayList ();
- for (index = 0, len = 0; index < this.length; index += len + 1) {
- len = splitme (separator, index);
- len = len > -1 ? len : this.length - index;
- if (len == 0) {
- list.Add (String.Empty);
- } else {
- char[] str;
- int i;
- str = new char [len + 1];
- for (i = 0; i < len; i++)
- str[i] = this.c_str[index + i];
- str[i] = '\0';
- list.Add (new String (str));
- }
- }
- strings = new string [list.Count];
- if (list.Count == 1) {
- /* special case for an array holding @this */
- strings[0] = this;
- } else {
- for (index = 0; index < list.Count; index++)
- strings[index] = (string) list[index];
- }
- return strings;
- }
- public string[] Split (char[] separator, int maxCount)
- {
- // FIXME: what to do if maxCount <= 0?
- // FIXME: would using Queue be better than ArrayList?
- string[] strings;
- ArrayList list;
- int index, len, used;
- used = 0;
- list = new ArrayList ();
- for (index = 0, len = 0; index < this.length && used < maxCount; index += len + 1) {
- len = splitme (separator, index);
- len = len > -1 ? len : this.length - index;
- if (len == 0) {
- list.Add (String.Empty);
- } else {
- char[] str;
- int i;
- str = new char [len + 1];
- for (i = 0; i < len; i++)
- str[i] = this.c_str[index + i];
- str[i] = '\0';
- list.Add (new String (str));
- }
- used++;
- }
- /* fit the remaining chunk of the @this into it's own element */
- if (index != this.length) {
- char[] str;
- int i;
- str = new char [this.length - index + 1];
- for (i = index; i < this.length; i++)
- str[i - index] = this.c_str[i];
- str[i - index] = '\0';
- list.Add (new String (str));
- }
- strings = new string [list.Count];
- if (list.Count == 1) {
- /* special case for an array holding @this */
- strings[0] = this;
- } else {
- for (index = 0; index < list.Count; index++)
- strings[index] = (string) list[index];
- }
- return strings;
- }
- public bool StartsWith (string value)
- {
- bool startswith = true;
- int i;
- if (value == null)
- throw new ArgumentNullException ();
- if (value.Length > this.length)
- return false;
- for (i = 0; i < value.Length && startswith; i++)
- startswith = startswith && value[i] == this.c_str[i];
- return startswith;
- }
- public string Substring (int startIndex)
- {
- char[] str;
- int i, len;
- if (startIndex < 0 || startIndex > this.length)
- throw new ArgumentOutOfRangeException ();
- len = this.length - startIndex;
- if (len == 0)
- return String.Empty;
- str = new char [len + 1];
- for (i = startIndex; i < this.length; i++)
- str[i - startIndex] = this.c_str[i];
- str[i] = '\0';
- return new String (str);
- }
- public string Substring (int startIndex, int length)
- {
- char[] str;
- int i;
- if (startIndex < 0 || length < 0 || startIndex + length > this.length)
- throw new ArgumentOutOfRangeException ();
- if (length == 0)
- return String.Empty;
- str = new char [length + 1];
- for (i = startIndex; i < startIndex + length; i++)
- str[i - startIndex] = this.c_str[i];
- str[i] = '\0';
- return new String (str);
- }
- public bool ToBoolean (IFormatProvider provider)
- {
- // FIXME: implement me
- return false;
- }
- public byte ToByte (IFormatProvider provider)
- {
- // FIXME: implement me
- return (byte) '\0';
- }
- public char ToChar (IFormatProvider provider)
- {
- // FIXME: implement me
- return '\0';
- }
- public char[] ToCharArray ()
- {
- return ToCharArray (0, this.length);
- }
- public char[] ToCharArray (int startIndex, int length)
- {
- char[] chars;
- int i;
- if (startIndex < 0 || length < 0 || startIndex + length > this.length)
- throw new ArgumentOutOfRangeException ();
- chars = new char [length + 1];
- for (i = startIndex; i < length; i++)
- chars[i - startIndex] = this.c_str[i];
- chars[length] = '\0';
- return chars;
- }
- public DateTime ToDateTime (IFormatProvider provider)
- {
- // FIXME: implement me
- return new DateTime (0);
- }
- public decimal ToDecimal (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0.0M;
- }
- public double ToDouble (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0.0;
- }
- public short ToInt16 (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0;
- }
- public int ToInt32 (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0;
- }
- public long ToInt64 (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0;
- }
- public string ToLower ()
- {
- char[] str;
- int i;
- str = new char [this.length + 1];
- for (i = 0; i < this.length; i++)
- str[i] = Char.ToLower (this.c_str[i]);
- str[i] = '\0';
- return new String (str);
- }
- public string ToLower (CultureInfo culture)
- {
- // FIXME: implement me
- return null;
- }
- public sbyte ToSByte (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0;
- }
- public float ToSingle (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0.0F;
- }
- public override string ToString ()
- {
- return Substring (0, this.length);
- }
- public string ToString (IFormatProvider format)
- {
- // FIXME: implement me
- return null;
- }
- public object ToType (Type conversionType, IFormatProvider provider)
- {
- // FIXME: implement me
- return null;
- }
- public ushort ToUInt16 (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0;
- }
- public uint ToUInt32 (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0;
- }
- public ulong ToUInt64 (IFormatProvider provider)
- {
- // FIXME: implement me
- return 0;
- }
- public string ToUpper ()
- {
- char[] str;
- int i;
- str = new char [this.length + 1];
- for (i = 0; i < this.length; i++)
- str[i] = Char.ToUpper (this.c_str[i]);
- str[i] = '\0';
- return new String (str);
- }
- public string ToUpper (CultureInfo culture)
- {
- // FIXME: implement me
- return null;
- }
- public string Trim ()
- {
- return Trim (null);
- }
- public string Trim (params char[] trimChars)
- {
- int begin, end;
- bool matches;
- matches = true;
- for (begin = 0; matches && begin < this.length; begin++) {
- if (trimChars != null) {
- matches = false;
- foreach (char c in trimChars) {
- matches = this.c_str[begin] == c;
- if (matches)
- break;
- }
- } else {
- matches = is_lwsp (this.c_str[begin]);
- }
- }
- matches = true;
- for (end = this.length; end > begin; end--) {
- if (trimChars != null) {
- matches = false;
- foreach (char c in trimChars) {
- matches = this.c_str[end] == c;
- if (matches)
- break;
- }
- } else {
- matches = is_lwsp (this.c_str[end]);
- }
- }
- if (begin == end)
- return String.Empty;
- return Substring (begin, end - begin);
- }
- public string TrimEnd (params char[] trimChars)
- {
- bool matches = true;
- int end;
- for (end = this.length; end > 0; end--) {
- if (trimChars != null) {
- matches = false;
- foreach (char c in trimChars) {
- matches = this.c_str[end] == c;
- if (matches)
- break;
- }
- } else {
- matches = is_lwsp (this.c_str[end]);
- }
- }
- if (end == 0)
- return String.Empty;
- return Substring (0, end);
- }
- public string TrimStart (params char[] trimChars)
- {
- bool matches = true;
- int begin;
- for (begin = 0; matches && begin < this.length; begin++) {
- if (trimChars != null) {
- matches = false;
- foreach (char c in trimChars) {
- matches = this.c_str[begin] == c;
- if (matches)
- break;
- }
- } else {
- matches = is_lwsp (this.c_str[begin]);
- }
- }
- if (begin == this.length)
- return String.Empty;
- return Substring (begin, this.length - begin);
- }
- // Operators
- public static bool operator ==(string a, string b)
- {
- if (a.length != b.length)
- return false;
- int l = a.length;
- for (int i = 0; i < l; i++)
- if (a.c_str [i] != b.c_str [i])
- return false;
- return true;
- }
- public static bool operator !=(string a, string b)
- {
- return !(a == b);
- }
- }
- }
|