diff options
Diffstat (limited to '')
-rw-r--r-- | src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp | 1327 |
1 files changed, 1327 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp new file mode 100644 index 00000000..76106a27 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp @@ -0,0 +1,1327 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher <darin@meer.net> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsString.h" + + + /** + * nsTString obsolete API support + */ + +#if MOZ_STRING_WITH_OBSOLETE_API + +#include "nsDependentString.h" +#include "nsDependentSubstring.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsUTF8Utils.h" +#include "prdtoa.h" +#include "prprf.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include <iprt/mem.h> +#endif + +/* ***** BEGIN RICKG BLOCK ***** + * + * NOTE: This section of code was extracted from rickg's bufferRoutines.h file. + * For the most part it remains unmodified. We want to eliminate (or at + * least clean up) this code at some point. If you find the formatting + * in this section somewhat inconsistent, don't blame me! ;-) + */ + +// XXXdarin what is wrong with STDC's tolower? +inline char +ascii_tolower(char aChar) +{ + if (aChar >= 'A' && aChar <= 'Z') + return aChar + ('a' - 'A'); + return aChar; +} + +//----------------------------------------------------------------------------- +// +// This set of methods is used to search a buffer looking for a char. +// + + +/** + * This methods cans the given buffer for the given char + * + * @update gess 02/17/00 + * @param aDest is the buffer to be searched + * @param aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length. + * @return index of pos if found, else -1 (kNotFound) + */ +static PRInt32 +FindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) { + + if(anOffset < 0) + anOffset=0; + + if(aCount < 0) + aCount = (PRInt32)aDestLength; + + if((aChar < 256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) { + + //We'll only search if the given aChar is within the normal ascii a range, + //(Since this string is definitely within the ascii range). + + if(0<aCount) { + + const char* left= aDest+anOffset; + const char* last= left+aCount; + const char* max = aDest+aDestLength; + const char* end = (last<max) ? last : max; + + PRInt32 theMax = end-left; + if(0<theMax) { + + unsigned char theChar = (unsigned char) aChar; + const char* result=(const char*)memchr(left, (int)theChar, theMax); + + if(result) + return result-aDest; + + } + } + } + + return kNotFound; +} + + +/** + * This methods cans the given buffer for the given char + * + * @update gess 3/25/98 + * @param aDest is the buffer to be searched + * @param aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length. + * @return index of pos if found, else -1 (kNotFound) + */ +static PRInt32 +FindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) { + + if(anOffset < 0) + anOffset=0; + + if(aCount < 0) + aCount = (PRInt32)aDestLength; + + if((0<aDestLength) && ((PRUint32)anOffset < aDestLength)) { + + if(0<aCount) { + + const PRUnichar* root = aDest; + const PRUnichar* left = root+anOffset; + const PRUnichar* last = left+aCount; + const PRUnichar* max = root+aDestLength; + const PRUnichar* end = (last<max) ? last : max; + + while(left<end){ + + if(*left==aChar) + return (left-root); + + ++left; + } + } + } + + return kNotFound; +} + + +/** + * This methods cans the given buffer (in reverse) for the given char + * + * @update gess 02/17/00 + * @param aDest is the buffer to be searched + * @param aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length. + * @return index of pos if found, else -1 (kNotFound) + */ + +static PRInt32 +RFindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) { + + if(anOffset < 0) + anOffset=(PRInt32)aDestLength-1; + + if(aCount < 0) + aCount = PRInt32(aDestLength); + + if((aChar<256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) { + + //We'll only search if the given aChar is within the normal ascii a range, + //(Since this string is definitely within the ascii range). + + if(0 < aCount) { + + const char* rightmost = aDest + anOffset; + const char* min = rightmost - aCount + 1; + const char* leftmost = (min<aDest) ? aDest: min; + + char theChar=(char)aChar; + while(leftmost <= rightmost){ + + if((*rightmost) == theChar) + return rightmost - aDest; + + --rightmost; + } + } + } + + return kNotFound; +} + + +/** + * This methods cans the given buffer for the given char + * + * @update gess 3/25/98 + * @param aDest is the buffer to be searched + * @param aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length. + * @return index of pos if found, else -1 (kNotFound) + */ +static PRInt32 +RFindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) { + + if(anOffset < 0) + anOffset=(PRInt32)aDestLength-1; + + if(aCount < 0) + aCount = PRInt32(aDestLength); + + if((0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) { + + if(0 < aCount) { + + const PRUnichar* root = aDest; + const PRUnichar* rightmost = root + anOffset; + const PRUnichar* min = rightmost - aCount + 1; + const PRUnichar* leftmost = (min<root) ? root: min; + + while(leftmost <= rightmost){ + + if((*rightmost) == aChar) + return rightmost - root; + + --rightmost; + } + } + } + + return kNotFound; +} + +//----------------------------------------------------------------------------- +// +// This set of methods is used to compare one buffer onto another. The +// functions are differentiated by the size of source and dest character +// sizes. WARNING: Your destination buffer MUST be big enough to hold all the +// source bytes. We don't validate these ranges here (this should be done in +// higher level routines). +// + + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +#ifdef __SUNPRO_CC +inline +#endif /* __SUNPRO_CC */ +PRInt32 +Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ + PRInt32 result=0; + if(aIgnoreCase) + result=PRInt32(PL_strncasecmp(aStr1, aStr2, aCount)); + else + result=nsCharTraits<char>::compare(aStr1,aStr2,aCount); + + // alien comparisons may return out-of-bound answers + // instead of the -1, 0, 1 expected by most clients + if ( result < -1 ) + result = -1; + else if ( result > 1 ) + result = 1; + return result; +} + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +#ifdef __SUNPRO_CC +inline +#endif /* __SUNPRO_CC */ +PRInt32 +Compare2To2(const PRUnichar* aStr1,const PRUnichar* aStr2,PRUint32 aCount){ + PRInt32 result; + + if ( aStr1 && aStr2 ) + result = nsCharTraits<PRUnichar>::compare(aStr1, aStr2, aCount); + + // The following cases are rare and survivable caller errors. + // Two null pointers are equal, but any string, even 0 length + // is greater than a null pointer. It might not really matter, + // but we pick something reasonable anyway. + else if ( !aStr1 && !aStr2 ) + result = 0; + else if ( aStr1 ) + result = 1; + else + result = -1; + + // alien comparisons may give answers outside the -1, 0, 1 expected by callers + if ( result < -1 ) + result = -1; + else if ( result > 1 ) + result = 1; + return result; +} + + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +#ifdef __SUNPRO_CC +inline +#endif /* __SUNPRO_CC */ +PRInt32 +Compare2To1(const PRUnichar* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ + const PRUnichar* s1 = aStr1; + const char *s2 = aStr2; + + if (aStr1 && aStr2) { + if (aCount != 0) { + do { + + PRUnichar c1 = *s1++; + PRUnichar c2 = PRUnichar((unsigned char)*s2++); + + if (c1 != c2) { +#ifdef NS_DEBUG + // we won't warn on c1>=128 (the 2-byte value) because often + // it is just fine to compare an constant, ascii value (i.e. "body") + // against some non-ascii value (i.e. a unicode string that + // was downloaded from a web page) + if (aIgnoreCase && c2>=128) + NS_WARNING("got a non-ASCII string, but we can't do an accurate case conversion!"); +#endif + + // can't do case conversion on characters out of our range + if (aIgnoreCase && c1<128 && c2<128) { + + c1 = ascii_tolower(char(c1)); + c2 = ascii_tolower(char(c2)); + + if (c1 == c2) continue; + } + + if (c1 < c2) return -1; + return 1; + } + } while (--aCount); + } + } + return 0; +} + + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +inline PRInt32 +Compare1To2(const char* aStr1,const PRUnichar* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ + return Compare2To1(aStr2, aStr1, aCount, aIgnoreCase) * -1; +} + + +//----------------------------------------------------------------------------- +// +// This set of methods is used compress char sequences in a buffer... +// + + +/** + * This method compresses duplicate runs of a given char from the given buffer + * + * @update rickg 03.23.2000 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +CompressChars1(char* aString,PRUint32 aLength,const char* aSet){ + + char* from = aString; + char* end = aString + aLength; + char* to = from; + + //this code converts /n, /t, /r into normal space ' '; + //it also compresses runs of whitespace down to a single char... + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + + while (from < end) { + char theChar = *from++; + + *to++=theChar; //always copy this char... + + if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ + while (from < end) { + theChar = *from++; + if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ + *to++ = theChar; + break; + } + } //while + } //if + } //if + *to = 0; + } + return to - aString; +} + + + +/** + * This method compresses duplicate runs of a given char from the given buffer + * + * @update rickg 03.23.2000 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +CompressChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){ + + PRUnichar* from = aString; + PRUnichar* end = from + aLength; + PRUnichar* to = from; + + //this code converts /n, /t, /r into normal space ' '; + //it also compresses runs of whitespace down to a single char... + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + + while (from < end) { + PRUnichar theChar = *from++; + + *to++=theChar; //always copy this char... + + if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ + while (from < end) { + theChar = *from++; + if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ + *to++ = theChar; + break; + } + } //while + } //if + } //if + *to = 0; + } + return to - (PRUnichar*)aString; +} + +/** + * This method strips chars in a given set from the given buffer + * + * @update gess 01/04/99 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +StripChars1(char* aString,PRUint32 aLength,const char* aSet){ + + // XXXdarin this code should defer writing until necessary. + + char* to = aString; + char* from = aString-1; + char* end = aString + aLength; + + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + while (++from < end) { + char theChar = *from; + if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ + *to++ = theChar; + } + } + *to = 0; + } + return to - (char*)aString; +} + + +/** + * This method strips chars in a given set from the given buffer + * + * @update gess 01/04/99 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +StripChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){ + + // XXXdarin this code should defer writing until necessary. + + PRUnichar* to = aString; + PRUnichar* from = aString-1; + PRUnichar* end = to + aLength; + + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + while (++from < end) { + PRUnichar theChar = *from; + //Note the test for ascii range below. If you have a real unicode char, + //and you're searching for chars in the (given) ascii string, there's no + //point in doing the real search since it's out of the ascii range. + if((255<theChar) || (kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ + *to++ = theChar; + } + } + *to = 0; + } + return to - (PRUnichar*)aString; +} + +/* ***** END RICKG BLOCK ***** */ + +static const char* kWhitespace="\b\t\r\n "; + +// This function is used to implement FindCharInSet and friends +template <class CharT> +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +CharT +GetFindInSetFilter( const CharT* set) + { + CharT filter = ~CharT(0); // All bits set + while (*set) { + filter &= ~(*set); + ++set; + } + return filter; + } + +// This template class is used by our code to access rickg's buffer routines. +template <class CharT> struct nsBufferRoutines {}; + +NS_SPECIALIZE_TEMPLATE +struct nsBufferRoutines<char> + { + static + PRInt32 compare( const char* a, const char* b, PRUint32 max, PRBool ic ) + { + return Compare1To1(a, b, max, ic); + } + + static + PRInt32 compare( const char* a, const PRUnichar* b, PRUint32 max, PRBool ic ) + { + return Compare1To2(a, b, max, ic); + } + + static + PRInt32 find_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return FindChar1(s, max, offset, c, count); + } + + static + PRInt32 rfind_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return RFindChar1(s, max, offset, c, count); + } + + static + char get_find_in_set_filter( const char* set ) + { + return GetFindInSetFilter(set); + } + + static + PRInt32 strip_chars( char* s, PRUint32 len, const char* set ) + { + return StripChars1(s, len, set); + } + + static + PRInt32 compress_chars( char* s, PRUint32 len, const char* set ) + { + return CompressChars1(s, len, set); + } + }; + +NS_SPECIALIZE_TEMPLATE +struct nsBufferRoutines<PRUnichar> + { + static + PRInt32 compare( const PRUnichar* a, const PRUnichar* b, PRUint32 max, PRBool ic ) + { + NS_ASSERTION(!ic, "no case-insensitive compare here"); + return Compare2To2(a, b, max); + } + + static + PRInt32 compare( const PRUnichar* a, const char* b, PRUint32 max, PRBool ic ) + { + return Compare2To1(a, b, max, ic); + } + + static + PRInt32 find_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return FindChar2(s, max, offset, c, count); + } + + static + PRInt32 rfind_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return RFindChar2(s, max, offset, c, count); + } + + static + PRUnichar get_find_in_set_filter( const PRUnichar* set ) + { + return GetFindInSetFilter(set); + } + + static + PRUnichar get_find_in_set_filter( const char* set ) + { + return (~PRUnichar(0)^~char(0)) | GetFindInSetFilter(set); + } + + static + PRInt32 strip_chars( PRUnichar* s, PRUint32 max, const char* set ) + { + return StripChars2(s, max, set); + } + + static + PRInt32 compress_chars( PRUnichar* s, PRUint32 len, const char* set ) + { + return CompressChars2(s, len, set); + } + }; + +//----------------------------------------------------------------------------- + +template <class L, class R> +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +FindSubstring( const L* big, PRUint32 bigLen, + const R* little, PRUint32 littleLen, + PRBool ignoreCase ) + { + if (littleLen > bigLen) + return kNotFound; + + PRInt32 i, max = PRInt32(bigLen - littleLen); + for (i=0; i<=max; ++i, ++big) + { + if (nsBufferRoutines<L>::compare(big, little, littleLen, ignoreCase) == 0) + return i; + } + + return kNotFound; + } + +template <class L, class R> +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +RFindSubstring( const L* big, PRUint32 bigLen, + const R* little, PRUint32 littleLen, + PRBool ignoreCase ) + { + if (littleLen > bigLen) + return kNotFound; + + PRInt32 i, max = PRInt32(bigLen - littleLen); + + const L* iter = big + max; + for (i=max; iter >= big; --i, --iter) + { + if (nsBufferRoutines<L>::compare(iter, little, littleLen, ignoreCase) == 0) + return i; + } + + return kNotFound; + } + +template <class CharT, class SetCharT> +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +FindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set ) + { + CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set); + + const CharT* end = data + dataLen; + for (const CharT* iter = data; iter < end; ++iter) + { + CharT currentChar = *iter; + if (currentChar & filter) + continue; // char is not in filter set; go on with next char. + + // test all chars + const SetCharT* charInSet = set; + CharT setChar = CharT(*charInSet); + while (setChar) + { + if (setChar == currentChar) + return iter - data; // found it! return index of the found char. + + setChar = CharT(*(++charInSet)); + } + } + return kNotFound; + } + +template <class CharT, class SetCharT> +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +RFindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set ) + { + CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set); + + for (const CharT* iter = data + dataLen - 1; iter >= data; --iter) + { + CharT currentChar = *iter; + if (currentChar & filter) + continue; // char is not in filter set; go on with next char. + + // test all chars + const CharT* charInSet = set; + CharT setChar = *charInSet; + while (setChar) + { + if (setChar == currentChar) + return iter - data; // found it! return index of the found char. + + setChar = *(++charInSet); + } + } + return kNotFound; + } + +/** + * This is a copy of |PR_cnvtf| with a bug fixed. (The second argument + * of PR_dtoa is 2 rather than 1.) + * + * XXXdarin if this is the right thing, then why wasn't it fixed in NSPR?!? + */ +void +Modified_cnvtf(char *buf, int bufsz, int prcsn, double fval) +{ + PRIntn decpt, sign, numdigits; + char *num, *nump; + char *bufp = buf; + char *endnum; + + /* If anything fails, we store an empty string in 'buf' */ +#ifdef VBOX_USE_IPRT_IN_XPCOM + num = (char*)RTMemAlloc(bufsz); +#else + num = (char*)malloc(bufsz); +#endif + if (num == NULL) { + buf[0] = '\0'; + return; + } + if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, bufsz) + == PR_FAILURE) { + buf[0] = '\0'; + goto done; + } + numdigits = endnum - num; + nump = num; + + /* + * The NSPR code had a fancy way of checking that we weren't dealing + * with -0.0 or -NaN, but I'll just use < instead. + * XXX Should we check !isnan(fval) as well? Is it portable? We + * probably don't need to bother since NAN isn't portable. + */ + if (sign && fval < 0.0f) { + *bufp++ = '-'; + } + + if (decpt == 9999) { + while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */ + goto done; + } + + if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) { + *bufp++ = *nump++; + if (numdigits != 1) { + *bufp++ = '.'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = 'e'; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1); + } + else if (decpt >= 0) { + if (decpt == 0) { + *bufp++ = '0'; + } + else { + while (decpt--) { + if (*nump != '\0') { + *bufp++ = *nump++; + } + else { + *bufp++ = '0'; + } + } + } + if (*nump != '\0') { + *bufp++ = '.'; + while (*nump != '\0') { + *bufp++ = *nump++; + } + } + *bufp++ = '\0'; + } + else if (decpt < 0) { + *bufp++ = '0'; + *bufp++ = '.'; + while (decpt++) { + *bufp++ = '0'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = '\0'; + } +done: +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(num); +#else + free(num); +#endif +} + + /** + * this method changes the meaning of |offset| and |count|: + * + * upon return, + * |offset| specifies start of search range + * |count| specifies length of search range + */ +static void +Find_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count ) + { + // |count| specifies how many iterations to make from |offset| + + if (offset < 0) + { + offset = 0; + } + else if (PRUint32(offset) > bigLen) + { + count = 0; + return; + } + + PRInt32 maxCount = bigLen - offset; + if (count < 0 || count > maxCount) + { + count = maxCount; + } + else + { + count += littleLen; + if (count > maxCount) + count = maxCount; + } + } + + /** + * this method changes the meaning of |offset| and |count|: + * + * upon entry, + * |offset| specifies the end point from which to search backwards + * |count| specifies the number of iterations from |offset| + * + * upon return, + * |offset| specifies start of search range + * |count| specifies length of search range + * + * + * EXAMPLE + * + * + -- littleLen=4 -- + + * : : + * |____|____|____|____|____|____|____|____|____|____|____|____| + * : : + * offset=5 bigLen=12 + * + * if count = 4, then we expect this function to return offset = 2 and + * count = 7. + * + */ +static void +RFind_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count ) + { + if (littleLen > bigLen) + { + offset = 0; + count = 0; + return; + } + + if (offset < 0) + offset = bigLen - littleLen; + if (count < 0) + count = offset + 1; + + PRInt32 start = offset - count + 1; + if (start < 0) + start = 0; + + count = offset + littleLen - start; + offset = start; + } + +//----------------------------------------------------------------------------- + + // define nsString obsolete methods +#include "string-template-def-unichar.h" +#include "nsTStringObsolete.cpp" +#include "string-template-undef.h" + + // define nsCString obsolete methods +#include "string-template-def-char.h" +#include "nsTStringObsolete.cpp" +#include "string-template-undef.h" + +//----------------------------------------------------------------------------- + +// specialized methods: + +PRInt32 +nsString::Find( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const + { + // this method changes the meaning of aOffset and aCount: + Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsString::Find( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const + { + return Find(nsDependentString(aString), aOffset, aCount); + } + +PRInt32 +nsString::RFind( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const + { + // this method changes the meaning of aOffset and aCount: + RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsString::RFind( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const + { + return RFind(nsDependentString(aString), aOffset, aCount); + } + +PRInt32 +nsString::FindCharInSet( const PRUnichar* aSet, PRInt32 aOffset ) const + { + if (aOffset < 0) + aOffset = 0; + else if (aOffset >= PRInt32(mLength)) + return kNotFound; + + PRInt32 result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet); + if (result != kNotFound) + result += aOffset; + return result; + } + + + /** + * nsTString::Compare,CompareWithConversion,etc. + */ + +PRInt32 +nsCString::Compare( const char* aString, PRBool aIgnoreCase, PRInt32 aCount ) const + { + PRUint32 strLen = char_traits::length(aString); + + PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen)); + + PRInt32 compareCount; + if (aCount < 0 || aCount > maxCount) + compareCount = maxCount; + else + compareCount = aCount; + + PRInt32 result = + nsBufferRoutines<char>::compare(mData, aString, compareCount, aIgnoreCase); + + if (result == 0 && + (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount))) + { + // Since the caller didn't give us a length to test, or strings shorter + // than aCount, and compareCount characters matched, we have to assume + // that the longer string is greater. + + if (mLength != strLen) + result = (mLength < strLen) ? -1 : 1; + } + return result; + } + +PRBool +nsString::EqualsIgnoreCase( const char* aString, PRInt32 aCount ) const + { + PRUint32 strLen = nsCharTraits<char>::length(aString); + + PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen)); + + PRInt32 compareCount; + if (aCount < 0 || aCount > maxCount) + compareCount = maxCount; + else + compareCount = aCount; + + PRInt32 result = + nsBufferRoutines<PRUnichar>::compare(mData, aString, compareCount, PR_TRUE); + + if (result == 0 && + (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount))) + { + // Since the caller didn't give us a length to test, or strings shorter + // than aCount, and compareCount characters matched, we have to assume + // that the longer string is greater. + + if (mLength != strLen) + result = 1; // Arbitrarily using any number != 0 + } + return result == 0; + } + + /** + * ToCString, ToFloat, ToInteger + */ + +char* +nsString::ToCString( char* aBuf, PRUint32 aBufLength, PRUint32 aOffset ) const + { + // because the old implementation checked aBuf + if (!(aBuf && aBufLength > 0 && aOffset <= mLength)) + return nsnull; + + PRUint32 maxCount = NS_MIN(aBufLength-1, mLength - aOffset); + + LossyConvertEncoding<PRUnichar, char> converter(aBuf); + converter.write(mData + aOffset, maxCount); + converter.write_terminator(); + return aBuf; + } + +float +nsCString::ToFloat(PRInt32* aErrorCode) const + { + float res = 0.0f; + if (mLength > 0) + { + char *conv_stopped; + const char *str = mData; + // Use PR_strtod, not strtod, since we don't want locale involved. + res = (float)PR_strtod(str, &conv_stopped); + if (conv_stopped == str+mLength) + *aErrorCode = (PRInt32) NS_OK; + else // Not all the string was scanned + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + else + { + // The string was too short (0 characters) + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + return res; + } + +float +nsString::ToFloat(PRInt32* aErrorCode) const + { + float res = 0.0f; + char buf[100]; + if (mLength > 0 && mLength < sizeof(buf)) + { + char *conv_stopped; + const char *str = ToCString(buf, sizeof(buf)); + // Use PR_strtod, not strtod, since we don't want locale involved. + res = (float)PR_strtod(str, &conv_stopped); + if (conv_stopped == str+mLength) + *aErrorCode = (PRInt32) NS_OK; + else // Not all the string was scanned + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + else + { + // The string was too short (0 characters) or too long (sizeof(buf)) + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + return res; + } + + + /** + * nsTString::AssignWithConversion + */ + +void +nsCString::AssignWithConversion( const nsAString& aData ) + { + LossyCopyUTF16toASCII(aData, *this); + } + +void +nsString::AssignWithConversion( const nsACString& aData ) + { + CopyASCIItoUTF16(aData, *this); + } + + + /** + * nsTString::AppendWithConversion + */ + +void +nsCString::AppendWithConversion( const nsAString& aData ) + { + LossyAppendUTF16toASCII(aData, *this); + } + +void +nsString::AppendWithConversion( const nsACString& aData ) + { + AppendASCIItoUTF16(aData, *this); + } + + + /** + * nsTString::AppendInt + */ + +void +nsCString::AppendInt( PRInt32 aInteger, PRInt32 aRadix ) + { + char buf[20]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%o"; + break; + case 10: + fmt = "%d"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%x"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + } + +void +nsString::AppendInt( PRInt32 aInteger, PRInt32 aRadix ) + { + char buf[20]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%o"; + break; + case 10: + fmt = "%d"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%x"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + AppendASCIItoUTF16(buf, *this); + } + +void +nsCString::AppendInt( PRInt64 aInteger, PRInt32 aRadix ) + { + char buf[30]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%llo"; + break; + case 10: + fmt = "%lld"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%llx"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + } + +void +nsString::AppendInt( PRInt64 aInteger, PRInt32 aRadix ) + { + char buf[30]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%llo"; + break; + case 10: + fmt = "%lld"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%llx"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + AppendASCIItoUTF16(buf, *this); + } + + /** + * nsTString::AppendFloat + */ + +void +nsCString::AppendFloat( double aFloat ) + { + char buf[40]; + // Use Modified_cnvtf, which is locale-insensitive, instead of the + // locale-sensitive PR_snprintf or sprintf(3) + Modified_cnvtf(buf, sizeof(buf), 6, aFloat); + Append(buf); + } + +void +nsString::AppendFloat( double aFloat ) + { + char buf[40]; + // Use Modified_cnvtf, which is locale-insensitive, instead of the + // locale-sensitive PR_snprintf or sprintf(3) + Modified_cnvtf(buf, sizeof(buf), 6, aFloat); + AppendWithConversion(buf); + } + +#endif // !MOZ_STRING_WITH_OBSOLETE_API |