/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include #include #include "nsString.h" #include "nsDebug.h" #include "nsDeque.h" #ifndef RICKG_TESTBED #include "prdtoa.h" #include "nsISizeOfHandler.h" #endif static const char* kNullPointerError = "Error: unexpected null ptr"; static const char* kWhitespace="\b\t\r\n "; static void Subsume(nsStr& aDest,nsStr& aSource){ if(aSource.mStr && aSource.mLength) { if(aSource.mOwnsBuffer){ nsStr::Destroy(aDest,0); aDest.mStr=aSource.mStr; aDest.mLength=aSource.mLength; aDest.mCharSize=aSource.mCharSize; aDest.mCapacity=aSource.mCapacity; aDest.mOwnsBuffer=aSource.mOwnsBuffer; aSource.mOwnsBuffer=PR_FALSE; aSource.mStr=0; } else{ nsStr::Assign(aDest,aSource,0,aSource.mLength,0); } } else nsStr::Truncate(aDest,0,0); } /** * Default constructor. */ nsString::nsString(nsIMemoryAgent* anAgent) : mAgent(anAgent) { nsStr::Initialize(*this,eTwoByte); } /** * This constructor accepts an ascii string * @update gess 1/4/99 * @param aCString is a ptr to a 1-byte cstr * @param aLength tells us how many chars to copy from given CString */ nsString::nsString(const char* aCString,nsIMemoryAgent* anAgent) : mAgent(anAgent) { nsStr::Initialize(*this,eTwoByte); Assign(aCString); } /** * This constructor accepts a unicode string * @update gess 1/4/99 * @param aString is a ptr to a unichar string * @param aLength tells us how many chars to copy from given aString */ nsString::nsString(const PRUnichar* aString,nsIMemoryAgent* anAgent) : mAgent(anAgent) { nsStr::Initialize(*this,eTwoByte); Assign(aString); } /** * This constructor works for all other nsSTr derivatives * @update gess 1/4/99 * @param reference to another nsCString */ nsString::nsString(const nsStr &aString,nsIMemoryAgent* anAgent) : mAgent(anAgent) { nsStr::Initialize(*this,eTwoByte); nsStr::Assign(*this,aString,0,aString.mLength,mAgent); } /** * This is our copy constructor * @update gess 1/4/99 * @param reference to another nsString */ nsString::nsString(const nsString& aString) :mAgent(aString.mAgent) { nsStr::Initialize(*this,eTwoByte); nsStr::Assign(*this,aString,0,aString.mLength,mAgent); } /** * construct from subsumeable string * @update gess 1/4/99 * @param reference to a subsumeString */ nsString::nsString(nsSubsumeStr& aSubsumeStr) :mAgent(0) { nsStr::Initialize(*this,eTwoByte); Subsume(*this,aSubsumeStr); } /** * Destructor * Make sure we call nsStr::Destroy. */ nsString::~nsString() { nsStr::Destroy(*this,mAgent); } void nsString::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const { if (aResult) { *aResult = sizeof(*this) + mCapacity * mCharSize; } } /** * This method truncates this string to given length. * * @update gess 01/04/99 * @param anIndex -- new length of string * @return nada */ void nsString::Truncate(PRInt32 anIndex) { nsStr::Truncate(*this,anIndex,mAgent); } /** * Determine whether or not the characters in this * string are in sorted order. * * @update gess 8/25/98 * @return TRUE if ordered. */ PRBool nsString::IsOrdered(void) const { PRBool result=PR_TRUE; if(mLength>1) { PRUint32 theIndex; PRUnichar c1=0; PRUnichar c2=GetCharAt(*this,0); for(theIndex=1;theIndexc2) { result=PR_FALSE; break; } } } return result; } /** * Call this method if you want to force the string to a certain capacity * @update gess 1/4/99 * @param aLength -- contains new length for mStr * @return */ void nsString::SetCapacity(PRUint32 aLength) { if(aLength>mCapacity) { GrowCapacity(*this,aLength,mAgent); } AddNullTerminator(*this); } /********************************************************************** Accessor methods... *********************************************************************/ //static char gChar=0; /** * * @update gess1/4/99 * @return ptr to internal buffer (if 1-byte), otherwise NULL */ const char* nsString::GetBuffer(void) const { const char* result=(eOneByte==mCharSize) ? mStr : 0; return result; } /** * This method returns the internal unicode buffer. * Now that we've factored the string class, this should never * be able to return a 1 byte string. * * @update gess1/4/99 * @return ptr to internal (2-byte) buffer; */ const PRUnichar* nsString::GetUnicode(void) const { const PRUnichar* result=(eOneByte==mCharSize) ? 0 : mUStr; return result; } /** * Get nth character. */ PRUnichar nsString::operator[](PRUint32 anIndex) const { return GetCharAt(*this,anIndex); } /** * Get nth character. */ PRUnichar nsString::CharAt(PRUint32 anIndex) const { return GetCharAt(*this,anIndex); } /** * Get 1st character. */ PRUnichar nsString::First(void) const{ return GetCharAt(*this,0); } /** * Get last character. */ PRUnichar nsString::Last(void) const{ return GetCharAt(*this,mLength-1); } /** * set a char inside this string at given index * @param aChar is the char you want to write into this string * @param anIndex is the ofs where you want to write the given char * @return TRUE if successful */ PRBool nsString::SetCharAt(PRUnichar aChar,PRUint32 anIndex){ PRBool result=PR_FALSE; if(anIndexmUStr, utf8len=0; 0 != (*p);p++) { if(0x0000 == ((*p) & 0x007F)) utf8len += 1; // 0000 0000 - 0000 007F else if(0x0000 == ((*p) & 0x07FF)) utf8len += 2; // 0000 0080 - 0000 07FF else utf8len += 3; // 0000 0800 - 0000 FFFF // Note: Surrogate pair need 4 bytes, but in this caculation // we count as 6 bytes. It will wast 2 bytes per surrogate pair } if((utf8len+1) > 8) temp.SetCapacity(utf8len+1); char* result=temp.mStr; char* out = result; PRUint32 ucs4=0; for(p = this->mUStr, utf8len=0; 0 != (*p);p++) { if(0 == ucs4) { if(0x0000 == ((*p) & 0xFF80)) { *out++ = (char)*p; } else if(0x0000 == ((*p) & 0xF800)) { *out++ = 0xC0 | (char)((*p) >> 6); *out++ = 0x80 | (char)(0x003F & (*p)); } else { if( 0xD800 == ( 0xFC00 & (*p))) { // D800- DBFF - High Surrogate // N = (H- D800) *400 + 10000 + ... ucs4 = 0x10000 | ((0x03FF & (*p)) << 10); } else if( 0xDC00 == ( 0xFC00 & (*p))) { // DC00- DFFF - Low Surrogate // error here. We should hit High Surrogate first // Do not output any thing in this case } else { *out++ = 0xE0 | (char)((*p) >> 12); *out++ = 0x80 | (char)(0x003F & (*p >> 6)); *out++ = 0x80 | (char)(0x003F & (*p) ); } } } else { if( 0xDC00 == (0xFC00 & (*p))) { // DC00- DFFF - Low Surrogate // N += ( L - DC00 ) ucs4 |= (0x03FF & (*p)); // 0001 0000-001F FFFF *out++ = 0xF0 | (char)(ucs4 >> 18); *out++ = 0x80 | (char)(0x003F & (ucs4 >> 12)); *out++ = 0x80 | (char)(0x003F & (ucs4 >> 6)); *out++ = 0x80 | (char)(0x003F & ucs4) ; } else { // Got a High Surrogate but no low surrogate // output nothing. } ucs4 = 0; } } *out = '\0'; // null terminate temp.mStr=0; temp.mOwnsBuffer=PR_FALSE; return result; } /** * Creates an ascii clone of this string * Note that calls to this method should be matched with calls to Recycle(). * @update gess 01/04/99 * @return ptr to new ascii string */ PRUnichar* nsString::ToNewUnicode() const { PRUnichar* result=0; if(eOneByte==mCharSize) { nsString temp(mStr); temp.SetCapacity(8); result=temp.mUStr; temp.mStr=0; temp.mOwnsBuffer=PR_FALSE; } else{ nsString temp(mUStr); temp.SetCapacity(8); result=temp.mUStr; temp.mStr=0; temp.mOwnsBuffer=PR_FALSE; } return result; } /** * Copies contents of this string into he given buffer * Note that if you provide me a buffer that is smaller than the length of * this string, only the number of bytes that will fit are copied. * * @update gess 01/04/99 * @param aBuf * @param aBufLength -- size of your external buffer (including null) * @param anOffset -- THIS IS NOT USED AT THIS TIME! * @return */ char* nsString::ToCString(char* aBuf, PRUint32 aBufLength,PRUint32 anOffset) const{ if(aBuf) { // NS_ASSERTION(mLength<=aBufLength,"buffer smaller than string"); CBufDescriptor theDescr(aBuf,PR_TRUE,aBufLength,0); nsCAutoString temp(theDescr); temp.Assign(*this,aBufLength-1); temp.mStr=0; } return aBuf; } /** * Perform string to float conversion. * @update gess 01/04/99 * @param aErrorCode will contain error if one occurs * @return float rep of string value */ float nsString::ToFloat(PRInt32* aErrorCode) const { char buf[100]; if (mLength > PRInt32(sizeof(buf)-1)) { *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; return 0.0f; } char* cp = ToCString(buf, sizeof(buf)); float f = (float) PR_strtod(cp, &cp); if (*cp != 0) { *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; } *aErrorCode = (PRInt32) NS_OK; return f; } /** * Perform numeric string to int conversion with given radix. * NOTE: 1. This method mandates that the string is well formed. * 2. This method will return an error if the string you give contains chars outside the range for the specified radix. * @update gess 10/01/98 * @param aErrorCode will contain error if one occurs * @param aRadix tells us what base to expect the string in. * @return int rep of string value */ static PRInt32 _ToInteger(nsCString& aString,PRInt32* anErrorCode,PRUint32 aRadix) { //copy chars to local buffer -- step down from 2 bytes to 1 if necessary... PRInt32 result=0; char* cp = aString.mStr + aString.mLength; PRInt32 theMult=1; *anErrorCode = NS_OK; //now iterate the numeric chars and build our result char theDigit=0; while(--cp>=aString.mStr){ char theChar=*cp; if((theChar>='0') && (theChar<='9')){ theDigit=theChar-'0'; } else if((theChar>='A') && (theChar<='F')) { if(10==aRadix){ *anErrorCode=NS_ERROR_ILLEGAL_VALUE; result=0; break; } theDigit=(theChar-'A')+10; } else if('-'==theChar) { result=-result; break; } else if(('+'==theChar) || (' '==theChar)) { //stop in a good state if you see this... break; } else { //we've encountered a char that's not a legal number or sign *anErrorCode=NS_ERROR_ILLEGAL_VALUE; result=0; break; } result+=theDigit*theMult; theMult*=aRadix; } return result; } /** * Call this method to extract the rightmost numeric value from the given * 1-byte input string, and simultaneously determine the radix. * NOTE: This method mandates that the string is well formed. * Leading and trailing gunk should be removed, and the case upper. * @update gess 10/01/98 * @param anInputString contains orig string * @param anOutString contains numeric portion copy of input string * @param aRadix (an out parm) tells the caller what base we think the string is in. * @return non-zero error code if this string is non-numeric */ static PRInt32 GetNumericSubstring(nsCString& aString,PRUint32& aRadix) { aString.ToUpperCase(); PRInt32 decPt=nsStr::FindChar(aString,'.',PR_TRUE,0); char* cp = (kNotFound==decPt) ? aString.mStr + aString.mLength-1 : aString.mStr+decPt-1; aRadix=kRadixUnknown; //assume for starters... // Skip trailing non-numeric... while (cp >= aString.mStr) { if((*cp>='0') && (*cp<='9')){ if(kRadixUnknown==aRadix) aRadix=kRadix10; break; } else if((*cp>='A') && (*cp<='F')) { aRadix=16; break; } cp--; } aString.Truncate(cp-aString.mStr+1); //ok, now scan through chars until you find the start of this number... //we delimit the number by the presence of: +,-,#,X // Skip trailing non-numeric... cp++; while (--cp >= aString.mStr) { if((*cp>='0') && (*cp<='9')){ continue; } else if((*cp>='A') && (*cp<='F')) { continue; } else if((*cp=='-') || (*cp=='+')){ break; } else { if(('#'==(*cp)) || ('X'==(*cp))) aRadix=kRadix16; cp++; //move back by one break; } } if(cp>aString.mStr) aString.Cut(0,cp-aString.mStr); PRInt32 result=(0==aString.mLength) ? NS_ERROR_ILLEGAL_VALUE : NS_OK; return result; } /** * This method tries to autodetect that radix given a string * @update gess 10/01/98 * @return 10,16,or 0 (meaning I don't know) */ PRUint32 nsString::DetermineRadix(void) { PRUint32 result=kRadixUnknown; if(0 36 || aRadix< 2) { /* no conversion if wrong base */ return *this; } if (aInteger < 0) *buffer++ = '-'; r = ldiv (labs(aInteger), aRadix); /* output digits of val/base first */ if (r.quot > 0) buffer = ltoa ( r.quot, buf, aRadix); /* output last digit */ int len=strlen(buffer); buf[len] = "0123456789abcdefghijklmnopqrstuvwxyz"[(int)r.rem]; buf[len+1] =0; return Append(buf); } /** * Append the given float to this string * @update gess 01/04/99 * @param aFloat: * @return */ nsString& nsString::Append(float aFloat){ char buf[40]; // *** XX UNCOMMENT THIS LINE //PR_snprintf(buf, sizeof(buf), "%g", aFloat); sprintf(buf,"%g",aFloat); Append(buf); return *this; } /* * Copies n characters from this left of this string to given string, * * @update gess 4/1/98 * @param aDest -- Receiving string * @param aCount -- number of chars to copy * @return number of chars copied */ PRUint32 nsString::Left(nsString& aDest,PRInt32 aCount) const{ if(aCount<0) aCount=mLength; else aCount=MinInt(aCount,mLength); nsStr::Assign(aDest,*this,0,aCount,mAgent); return aDest.mLength; } /* * Copies n characters from this string to from given offset * * @update gess 4/1/98 * @param aDest -- Receiving string * @param anOffset -- where copying should begin * @param aCount -- number of chars to copy * @return number of chars copied */ PRUint32 nsString::Mid(nsString& aDest,PRUint32 anOffset,PRInt32 aCount) const{ if(aCount<0) aCount=mLength; else aCount=MinInt(aCount,mLength); nsStr::Assign(aDest,*this,anOffset,aCount,mAgent); return aDest.mLength; } /* * Copies last n characters from this string to given string, * * @update gess 4/1/98 * @param aDest -- Receiving string * @param aCount -- number of chars to copy * @return number of chars copied */ PRUint32 nsString::Right(nsString& aDest,PRInt32 aCount) const{ PRInt32 offset=MaxInt(mLength-aCount,0); return Mid(aDest,offset,aCount); } /* * This method inserts n chars from given string into this * string at str[anOffset]. * * @update gess 4/1/98 * @param aString -- source String to be inserted into this * @param anOffset -- insertion position within this str * @param aCount -- number of chars to be copied from aCopy * @return this */ nsString& nsString::Insert(const nsString& aCopy,PRUint32 anOffset,PRInt32 aCount) { nsStr::Insert(*this,anOffset,aCopy,0,aCount,mAgent); return *this; } /** * Insert a char* into this string at a specified offset. * * @update gess4/22/98 * @param char* aCString to be inserted into this string * @param anOffset is insert pos in str * @param aCounttells us how many chars to insert * @return this */ nsString& nsString::Insert(const char* aCString,PRUint32 anOffset,PRInt32 aCount){ if(aCString && aCount){ nsStr temp; nsStr::Initialize(temp,eOneByte); temp.mStr=(char*)aCString; if(0> 1; PRUnichar theChar=GetCharAt(*this,middle); if (theChar==aChar) return middle; if (theChar>aChar) high = middle - 1; else low = middle + 1; } return kNotFound; } /** * Search for given cstr within this string * * @update gess 3/25/98 * @param aCString - substr to be found * @return offset in string, or -1 (kNotFound) */ PRInt32 nsString::Find(const char* aCString,PRBool aIgnoreCase,PRInt32 anOffset) const{ NS_ASSERTION(0!=aCString,kNullPointerError); PRInt32 result=kNotFound; if(aCString) { nsStr temp; nsStr::Initialize(temp,eOneByte); temp.mLength=nsCRT::strlen(aCString); temp.mStr=(char*)aCString; result=nsStr::FindSubstr(*this,temp,aIgnoreCase,anOffset); } return result; } /** * Search for given unichar* within this string * * @update gess 3/25/98 * @param aString - substr to be found * @return offset in string, or -1 (kNotFound) */ PRInt32 nsString::Find(const PRUnichar* aString,PRBool aIgnoreCase,PRInt32 anOffset) const{ NS_ASSERTION(0!=aString,kNullPointerError); PRInt32 result=kNotFound; if(aString) { nsStr temp; nsStr::Initialize(temp,eTwoByte); temp.mLength=nsCRT::strlen(aString); temp.mUStr=(PRUnichar*)aString; result=nsStr::FindSubstr(*this,temp,aIgnoreCase,anOffset); } return result; } /** * Search for given nsSTr within this string * * @update gess 3/25/98 * @param aString - substr to be found * @return offset in string, or -1 (kNotFound) */ PRInt32 nsString::Find(const nsStr& aString,PRBool aIgnoreCase,PRInt32 anOffset) const{ PRInt32 result=nsStr::FindSubstr(*this,aString,aIgnoreCase,anOffset); return result; } /** * Search for given string within this string * * @update gess 3/25/98 * @param aString - substr to be found * @return offset in string, or -1 (kNotFound) */ PRInt32 nsString::Find(const nsString& aString,PRBool aIgnoreCase,PRInt32 anOffset) const{ PRInt32 result=nsStr::FindSubstr(*this,aString,aIgnoreCase,anOffset); return result; } /** * Search for a given char, starting at given offset * * @update gess 3/25/98 * @param aChar * @return offset of found char, or -1 (kNotFound) */ #if 0 PRInt32 nsString::Find(PRUnichar aChar,PRInt32 anOffset,PRBool aIgnoreCase) const{ PRInt32 result=nsStr::FindChar(*this,aChar,aIgnoreCase,anOffset); return result; } #endif /** * Search for a given char, starting at given offset * * @update gess 3/25/98 * @param aChar is the unichar to be sought * @param anOffset * @param aIgnoreCase * @return offset of found char, or -1 (kNotFound) */ PRInt32 nsString::FindChar(PRUnichar aChar,PRBool aIgnoreCase,PRInt32 anOffset) const{ PRInt32 result=nsStr::FindChar(*this,aChar,aIgnoreCase,anOffset); return result; } /** * This method finds the offset of the first char in this string that is * a member of the given charset, starting the search at anOffset * * @update gess 3/25/98 * @param aCStringSet * @param anOffset -- where in this string to start searching * @return */ PRInt32 nsString::FindCharInSet(const char* aCStringSet,PRInt32 anOffset) const{ NS_ASSERTION(0!=aCStringSet,kNullPointerError); PRInt32 result=kNotFound; if(aCStringSet) { nsStr temp; nsStr::Initialize(temp,eOneByte); temp.mLength=nsCRT::strlen(aCStringSet); temp.mStr=(char*)aCStringSet; result=nsStr::FindCharInSet(*this,temp,PR_FALSE,anOffset); } return result; } /** * This method finds the offset of the first char in this string that is * a member of the given charset, starting the search at anOffset * * @update gess 3/25/98 * @param aCStringSet * @param anOffset -- where in this string to start searching * @return */ PRInt32 nsString::FindCharInSet(const PRUnichar* aStringSet,PRInt32 anOffset) const{ NS_ASSERTION(0!=aStringSet,kNullPointerError); PRInt32 result=kNotFound; if(aStringSet) { nsStr temp; nsStr::Initialize(temp,eTwoByte); temp.mLength=nsCRT::strlen(aStringSet); temp.mStr=(char*)aStringSet; result=nsStr::FindCharInSet(*this,temp,PR_FALSE,anOffset); } return result; } /** * This method finds the offset of the first char in this string that is * a member of the given charset, starting the search at anOffset * * @update gess 3/25/98 * @param aCStringSet * @param anOffset -- where in this string to start searching * @return */ PRInt32 nsString::FindCharInSet(const nsStr& aSet,PRInt32 anOffset) const{ PRInt32 result=nsStr::FindCharInSet(*this,aSet,PR_FALSE,anOffset); return result; } /** * * * @update gess 3/25/98 * @param * @return */ PRInt32 nsString::RFind(const nsStr& aString,PRBool aIgnoreCase,PRInt32 anOffset) const{ PRInt32 result=nsStr::RFindSubstr(*this,aString,aIgnoreCase,anOffset); return result; } /** * Reverse search for substring * * @update gess 3/25/98 * @param aString * @param aIgnoreCase * @param anOffset - tells us where to begin the search * @return offset of substring or -1 */ PRInt32 nsString::RFind(const nsString& aString,PRBool aIgnoreCase,PRInt32 anOffset) const{ PRInt32 result=nsStr::RFindSubstr(*this,aString,aIgnoreCase,anOffset); return result; } /** * Reverse search for substring * * @update gess 3/25/98 * @param aString * @param aIgnoreCase * @param anOffset - tells us where to begin the search * @return offset of substring or -1 */ PRInt32 nsString::RFind(const char* aString,PRBool aIgnoreCase,PRInt32 anOffset) const{ NS_ASSERTION(0!=aString,kNullPointerError); PRInt32 result=kNotFound; if(aString) { nsStr temp; nsStr::Initialize(temp,eOneByte); temp.mLength=nsCRT::strlen(aString); temp.mStr=(char*)aString; result=nsStr::RFindSubstr(*this,temp,aIgnoreCase,anOffset); } return result; } /** * Reverse search for char * * @update gess 3/25/98 * @param achar * @param aIgnoreCase * @param anOffset - tells us where to begin the search * @return offset of substring or -1 */ #if 0 PRInt32 nsString::RFind(PRUnichar aChar,PRInt32 anOffset,PRBool aIgnoreCase) const{ PRInt32 result=nsStr::RFindChar(*this,aChar,aIgnoreCase,anOffset); return result; } #endif /** * Reverse search for a given char, starting at given offset * * @update gess 3/25/98 * @param aChar * @param aIgnoreCase * @param anOffset * @return offset of found char, or -1 (kNotFound) */ PRInt32 nsString::RFindChar(PRUnichar aChar,PRBool aIgnoreCase,PRInt32 anOffset) const{ PRInt32 result=nsStr::RFindChar(*this,aChar,aIgnoreCase,anOffset); return result; } /** * Reverse search for char in this string that is also a member of given charset * * @update gess 3/25/98 * @param aCStringSet * @param anOffset * @return offset of found char, or -1 (kNotFound) */ PRInt32 nsString::RFindCharInSet(const char* aCStringSet,PRInt32 anOffset) const{ NS_ASSERTION(0!=aCStringSet,kNullPointerError); PRInt32 result=kNotFound; if(aCStringSet) { nsStr temp; nsStr::Initialize(temp,eOneByte); temp.mLength=nsCRT::strlen(aCStringSet); temp.mStr=(char*)aCStringSet; result=nsStr::RFindCharInSet(*this,temp,PR_FALSE,anOffset); } return result; } /** * Reverse search for a first char in this string that is a * member of the given char set * * @update gess 3/25/98 * @param aSet * @param aIgnoreCase * @param anOffset * @return offset of found char, or -1 (kNotFound) */ PRInt32 nsString::RFindCharInSet(const nsStr& aSet,PRInt32 anOffset) const{ PRInt32 result=nsStr::RFindCharInSet(*this,aSet,PR_FALSE,anOffset); return result; } /** * Reverse search for a first char in this string that is a * member of the given char set * * @update gess 3/25/98 * @param aSet * @param aIgnoreCase * @param anOffset * @return offset of found char, or -1 (kNotFound) */ PRInt32 nsString::RFindCharInSet(const PRUnichar* aStringSet,PRInt32 anOffset) const{ NS_ASSERTION(0!=aStringSet,kNullPointerError); PRInt32 result=kNotFound; if(aStringSet) { nsStr temp; nsStr::Initialize(temp,eTwoByte); temp.mLength=nsCRT::strlen(aStringSet); temp.mUStr=(PRUnichar*)aStringSet; result=nsStr::RFindCharInSet(*this,temp,PR_FALSE,anOffset); } return result; } /************************************************************** COMPARISON METHODS... **************************************************************/ /** * Compares given cstring to this string. * @update gess 01/04/99 * @param aCString pts to a cstring * @param aIgnoreCase tells us how to treat case * @param aCount tells us how many chars to test; -1 implies full length * @return -1,0,1 */ PRInt32 nsString::Compare(const nsString& aString,PRBool aIgnoreCase,PRInt32 aCount) const { PRInt32 result=nsStr::Compare(*this,aString,aCount,aIgnoreCase); return result; } /** * Compares given cstring to this string. * @update gess 01/04/99 * @param aCString pts to a cstring * @param aIgnoreCase tells us how to treat case * @param aCount tells us how many chars to test; -1 implies full length * @return -1,0,1 */ PRInt32 nsString::Compare(const char *aCString,PRBool aIgnoreCase,PRInt32 aCount) const { NS_ASSERTION(0!=aCString,kNullPointerError); if(aCString) { nsStr temp; nsStr::Initialize(temp,eOneByte); temp.mLength=nsCRT::strlen(aCString); temp.mStr=(char*)aCString; return nsStr::Compare(*this,temp,aCount,aIgnoreCase); } return 0; } /** * Compares given unistring to this string. * @update gess 01/04/99 * @param aString pts to a uni-string * @param aIgnoreCase tells us how to treat case * @param aCount tells us how many chars to test; -1 implies full length * @return -1,0,1 */ PRInt32 nsString::Compare(const PRUnichar* aString,PRBool aIgnoreCase,PRInt32 aCount) const { NS_ASSERTION(0!=aString,kNullPointerError); if(aString) { nsStr temp; nsStr::Initialize(temp,eTwoByte); temp.mLength=nsCRT::strlen(aString); temp.mUStr=(PRUnichar*)aString; return nsStr::Compare(*this,temp,aCount,aIgnoreCase); } return 0; } /** * Compare given nsStr with this cstring. * * @param aString is an nsStr instance to be compared * @param aIgnoreCase tells us how to treat case * @param aCount tells us how many chars to test; -1 implies full length * @return -1,0,1 */ PRInt32 nsString::Compare(const nsStr& aString,PRBool aIgnoreCase,PRInt32 aCount) const { return nsStr::Compare(*this,aString,aCount,aIgnoreCase); } /** * Here come a whole bunch of operator functions that are self-explanatory... */ PRBool nsString::operator==(const nsString& S) const {return Equals(S);} PRBool nsString::operator==(const nsStr& S) const {return Equals(S);} PRBool nsString::operator==(const char* s) const {return Equals(s);} PRBool nsString::operator==(const PRUnichar* s) const {return Equals(s);} PRBool nsString::operator!=(const nsString& S) const {return PRBool(Compare(S)!=0);} PRBool nsString::operator!=(const nsStr& S) const {return PRBool(Compare(S)!=0);} PRBool nsString::operator!=(const char* s) const {return PRBool(Compare(s)!=0);} PRBool nsString::operator!=(const PRUnichar* s) const {return PRBool(Compare(s)!=0);} PRBool nsString::operator<(const nsString& S) const {return PRBool(Compare(S)<0);} PRBool nsString::operator<(const nsStr& S) const {return PRBool(Compare(S)<0);} PRBool nsString::operator<(const char* s) const {return PRBool(Compare(s)<0);} PRBool nsString::operator<(const PRUnichar* s) const {return PRBool(Compare(s)<0);} PRBool nsString::operator>(const nsString& S) const {return PRBool(Compare(S)>0);} PRBool nsString::operator>(const nsStr& S) const {return PRBool(Compare(S)>0);} PRBool nsString::operator>(const char* s) const {return PRBool(Compare(s)>0);} PRBool nsString::operator>(const PRUnichar* s) const {return PRBool(Compare(s)>0);} PRBool nsString::operator<=(const nsString& S) const {return PRBool(Compare(S)<=0);} PRBool nsString::operator<=(const nsStr& S) const {return PRBool(Compare(S)<=0);} PRBool nsString::operator<=(const char* s) const {return PRBool(Compare(s)<=0);} PRBool nsString::operator<=(const PRUnichar* s) const {return PRBool(Compare(s)<=0);} PRBool nsString::operator>=(const nsString& S) const {return PRBool(Compare(S)>=0);} PRBool nsString::operator>=(const nsStr& S) const {return PRBool(Compare(S)>=0);} PRBool nsString::operator>=(const char* s) const {return PRBool(Compare(s)>=0);} PRBool nsString::operator>=(const PRUnichar* s) const {return PRBool(Compare(s)>=0);} PRBool nsString::EqualsIgnoreCase(const nsString& aString) const { return Equals(aString,PR_TRUE); } PRBool nsString::EqualsIgnoreCase(const char* aString,PRInt32 aLength) const { return Equals(aString,PR_TRUE,aLength); } PRBool nsString::EqualsIgnoreCase(/*FIX: const */nsIAtom *aAtom) const { return Equals(aAtom,PR_TRUE); } PRBool nsString::EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const { return Equals(s1,s2,PR_TRUE); } /** * Compare this to given string; note that we compare full strings here. * * @update gess 01/04/99 * @param aString is the other nsString to be compared to * @param aCount tells us how many chars to test; -1 implies full length * @return TRUE if equal */ PRBool nsString::Equals(const nsString& aString,PRBool aIgnoreCase,PRInt32 aCount) const { PRInt32 theAnswer=nsStr::Compare(*this,aString,aCount,aIgnoreCase); PRBool result=PRBool(0==theAnswer); return result; } /** * Compare this to given string; note that we compare full strings here. * * @update gess 01/04/99 * @param aString is the other nsString to be compared to * @param aCount tells us how many chars to test; -1 implies full length * @return TRUE if equal */ PRBool nsString::Equals(const nsStr& aString,PRBool aIgnoreCase,PRInt32 aCount) const { PRInt32 theAnswer=nsStr::Compare(*this,aString,aCount,aIgnoreCase); PRBool result=PRBool(0==theAnswer); return result; } /** * Compare this to given c-string; note that we compare full strings here. * * @param aString is the CString to be compared * @param aIgnorecase tells us whether to be case sensitive * @param aCount tells us how many chars to test; -1 implies full length * @return TRUE if equal */ PRBool nsString::Equals(const char* aString,PRBool aIgnoreCase,PRInt32 aCount) const { PRInt32 theAnswer=Compare(aString,aIgnoreCase,aCount); PRBool result=PRBool(0==theAnswer); return result; } /** * Compare this to given unicode string; note that we compare full strings here. * * @param aString is the U-String to be compared * @param aIgnorecase tells us whether to be case sensitive * @param aCount tells us how many chars to test; -1 implies full length * @return TRUE if equal */ PRBool nsString::Equals(const PRUnichar* aString,PRBool aIgnoreCase,PRInt32 aCount) const { PRInt32 theAnswer=Compare(aString,aIgnoreCase,aCount); PRBool result=PRBool(0==theAnswer); return result; } /** * Compare this to given atom; note that we compare full strings here. * The optional length argument just lets us know how long the given string is. * If you provide a length, it is compared to length of this string as an * optimization. * * @update gess 01/04/99 * @param aString -- unistring to compare to this * @param aLength -- length of given string. * @return TRUE if equal */ PRBool nsString::Equals(/*FIX: const */nsIAtom* aAtom,PRBool aIgnoreCase) const{ NS_ASSERTION(0!=aAtom,kNullPointerError); PRBool result=PR_FALSE; if(aAtom){ PRInt32 cmp=0; const PRUnichar* unicode; if (aAtom->GetUnicode(&unicode) != NS_OK || unicode == nsnull) return PR_FALSE; if (aIgnoreCase) cmp=nsCRT::strcasecmp(mUStr,unicode); else cmp=nsCRT::strcmp(mUStr,unicode); result=PRBool(0==cmp); } return result; } /** * Compare given strings * @update gess 7/27/98 * @param s1 -- first unichar string to be compared * @param s2 -- second unichar string to be compared * @return TRUE if equal */ PRBool nsString::Equals(const PRUnichar* s1, const PRUnichar* s2,PRBool aIgnoreCase) const { NS_ASSERTION(0!=s1,kNullPointerError); NS_ASSERTION(0!=s2,kNullPointerError); PRBool result=PR_FALSE; if((s1) && (s2)){ PRInt32 cmp=(aIgnoreCase) ? nsCRT::strcasecmp(s1,s2) : nsCRT::strcmp(s1,s2); result=PRBool(0==cmp); } return result; } /** * Determine if given char in valid alpha range * * @update gess 3/31/98 * @param aChar is character to be tested * @return TRUE if in alpha range */ PRBool nsString::IsAlpha(PRUnichar aChar) { // XXX i18n if (((aChar >= 'A') && (aChar <= 'Z')) || ((aChar >= 'a') && (aChar <= 'z'))) { return PR_TRUE; } return PR_FALSE; } /** * Determine if given char is a valid space character * * @update gess 3/31/98 * @param aChar is character to be tested * @return TRUE if is valid space char */ PRBool nsString::IsSpace(PRUnichar aChar) { // XXX i18n if ((aChar == ' ') || (aChar == '\r') || (aChar == '\n') || (aChar == '\t')) { return PR_TRUE; } return PR_FALSE; } /** * Determine if given buffer contains plain ascii * * @param aBuffer -- if null, then we test *this, otherwise we test given buffer * @return TRUE if is all ascii chars, or if strlen==0 */ PRBool nsString::IsASCII(const PRUnichar* aBuffer) { if(!aBuffer) { aBuffer=mUStr; if(eOneByte==mCharSize) return PR_TRUE; } if(aBuffer) { while(*aBuffer) { if(*aBuffer>255){ return PR_FALSE; } aBuffer++; } } return PR_TRUE; } /** * Determine if given char is valid digit * * @update gess 3/31/98 * @param aChar is character to be tested * @return TRUE if char is a valid digit */ PRBool nsString::IsDigit(PRUnichar aChar) { // XXX i18n return PRBool((aChar >= '0') && (aChar <= '9')); } #ifndef RICKG_TESTBED /************************************************************** Define the string deallocator class... **************************************************************/ class nsStringDeallocator: public nsDequeFunctor{ public: virtual void* operator()(void* anObject) { static nsMemoryAgent theAgent; nsString* aString= (nsString*)anObject; if(aString){ aString->mAgent=&theAgent; delete aString; } return 0; } }; /**************************************************************************** * This class, appropriately enough, creates and recycles nsString objects.. ****************************************************************************/ class nsStringRecycler { public: nsStringRecycler() : mDeque(0) { } ~nsStringRecycler() { nsStringDeallocator theDeallocator; mDeque.ForEach(theDeallocator); //now delete the strings } void Recycle(nsString* aString) { mDeque.Push(aString); } nsString* CreateString(void){ nsString* result=(nsString*)mDeque.Pop(); if(!result) result=new nsString(); return result; } nsDeque mDeque; }; static nsStringRecycler& GetRecycler(void); /** * * @update gess 01/04/99 * @param * @return */ nsStringRecycler& GetRecycler(void){ static nsStringRecycler gRecycler; return gRecycler; } #endif /** * Call this mehod when you're done * @update gess 01/04/99 * @param * @return */ nsString* nsString::CreateString(void){ nsString* result=0; #ifndef RICKG_TESTBED GetRecycler().CreateString(); #endif return result; } /** * Call this mehod when you're done * @update gess 01/04/99 * @param * @return */ void nsString::Recycle(nsString* aString){ #ifndef RICKG_TESTBED GetRecycler().Recycle(aString); #else delete aString; #endif } #if 0 /** * * @update gess 01/04/99 * @param * @return */ void nsString::DebugDump(ostream& aStream) const { for(PRUint32 i=0;i= PRInt32(sizeof(buf))) { cp = aString.ToNewCString(); } else { aString.ToCString(cp, len + 1); } if(len>0) ::fwrite(cp, 1, len, out); if (cp != buf) { delete[] cp; } return (int) len; } /*********************************************************************** IMPLEMENTATION NOTES: AUTOSTRING... ***********************************************************************/ /** * Default constructor * */ nsAutoString::nsAutoString() : nsString() { nsStr::Initialize(*this,mBuffer,(sizeof(mBuffer)>>eTwoByte)-1,0,eTwoByte,PR_FALSE); mAgent=0; AddNullTerminator(*this); } /** * Copy construct from ascii c-string * @param aCString is a ptr to a 1-byte cstr * @param aLength tells us how many chars to copy from aCString */ nsAutoString::nsAutoString(const char* aCString,PRInt32 aLength) : nsString() { nsStr::Initialize(*this,mBuffer,(sizeof(mBuffer)>>eTwoByte)-1,0,eTwoByte,PR_FALSE); mAgent=0; AddNullTerminator(*this); Append(aCString,aLength); } /** * Copy construct from uni-string * @param aString is a ptr to a unistr * @param aLength tells us how many chars to copy from aString */ nsAutoString::nsAutoString(const PRUnichar* aString,PRInt32 aLength) : nsString() { mAgent=0; nsStr::Initialize(*this,mBuffer,(sizeof(mBuffer)>>eTwoByte)-1,0,eTwoByte,PR_FALSE); AddNullTerminator(*this); Append(aString,aLength); } /** * constructor that uses external buffer * @param aBuffer describes the external buffer */ nsAutoString::nsAutoString(const CBufDescriptor& aBuffer) : nsString() { mAgent=0; if(!aBuffer.mBuffer) { nsStr::Initialize(*this,mBuffer,(sizeof(mBuffer)>>eTwoByte)-1,0,eTwoByte,PR_FALSE); } else { nsStr::Initialize(*this,aBuffer.mBuffer,aBuffer.mCapacity,aBuffer.mLength,aBuffer.mCharSize,!aBuffer.mStackBased); } if(!aBuffer.mIsConst) AddNullTerminator(*this); } /** * Copy construct from an nsStr * @param */ nsAutoString::nsAutoString(const nsStr& aString) : nsString() { mAgent=0; nsStr::Initialize(*this,mBuffer,(sizeof(mBuffer)>>eTwoByte)-1,0,eTwoByte,PR_FALSE); AddNullTerminator(*this); Append(aString); } /** * Default copy constructor */ nsAutoString::nsAutoString(const nsAutoString& aString) : nsString() { mAgent=0; nsStr::Initialize(*this,mBuffer,(sizeof(mBuffer)>>eTwoByte)-1,0,eTwoByte,PR_FALSE); AddNullTerminator(*this); Append(aString); } /** * Copy construct from a unichar * @param */ nsAutoString::nsAutoString(PRUnichar aChar) : nsString(){ mAgent=0; nsStr::Initialize(*this,mBuffer,(sizeof(mBuffer)>>eTwoByte)-1,0,eTwoByte,PR_FALSE); AddNullTerminator(*this); Append(aChar); } /** * construct from a subsumeable string * @update gess 1/4/99 * @param reference to a subsumeString */ #ifdef AIX nsAutoString::nsAutoString(const nsSubsumeStr& aSubsumeStr) :nsString() { mAgent=0; nsSubsumeStr temp(aSubsumeStr); // a temp is needed for the AIX compiler Subsume(*this,temp); #else nsAutoString::nsAutoString( nsSubsumeStr& aSubsumeStr) :nsString() { mAgent=0; Subsume(*this,aSubsumeStr); #endif // AIX } /** * deconstruct the autstring * @param */ nsAutoString::~nsAutoString(){ } void nsAutoString::SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const { if (aResult) { *aResult = sizeof(*this) + mCapacity * mCharSize; } } nsSubsumeStr::nsSubsumeStr(nsStr& aString) : nsString() { Subsume(*this,aString); } nsSubsumeStr::nsSubsumeStr(PRUnichar* aString,PRBool assumeOwnership,PRInt32 aLength) : nsString() { mUStr=aString; mCapacity=mLength=(-1==aLength) ? nsCRT::strlen(aString) : aLength; mOwnsBuffer=assumeOwnership; } nsSubsumeStr::nsSubsumeStr(char* aString,PRBool assumeOwnership,PRInt32 aLength) : nsString() { mStr=aString; mCharSize=eOneByte; mCapacity=mLength=(-1==aLength) ? strlen(aString) : aLength; mOwnsBuffer=assumeOwnership; }