Back to index

lightning-sunbird  0.9+nobinonly
nsStringObsolete.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set ts=2 sw=2 sts=2 et cindent: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla.
00017  *
00018  * The Initial Developer of the Original Code is IBM Corporation.
00019  * Portions created by IBM Corporation are Copyright (C) 2003
00020  * IBM Corporation. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Darin Fisher <darin@meer.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsString.h"
00040 
00041 
00046 #if MOZ_STRING_WITH_OBSOLETE_API
00047 
00048 #include "nsDependentString.h"
00049 #include "nsDependentSubstring.h"
00050 #include "nsReadableUtils.h"
00051 #include "nsCRT.h"
00052 #include "nsUTF8Utils.h"
00053 #include "prdtoa.h"
00054 #include "prprf.h"
00055 
00056 /* ***** BEGIN RICKG BLOCK *****
00057  *
00058  * NOTE: This section of code was extracted from rickg's bufferRoutines.h file.
00059  *       For the most part it remains unmodified.  We want to eliminate (or at
00060  *       least clean up) this code at some point.  If you find the formatting
00061  *       in this section somewhat inconsistent, don't blame me! ;-)
00062  */
00063 
00064 // avoid STDC's tolower since it may do weird things with non-ASCII bytes
00065 inline char
00066 ascii_tolower(char aChar)
00067 {
00068   if (aChar >= 'A' && aChar <= 'Z')
00069     return aChar + ('a' - 'A');
00070   return aChar;
00071 }
00072 
00073 //-----------------------------------------------------------------------------
00074 //
00075 //  This set of methods is used to search a buffer looking for a char.
00076 //
00077 
00078 
00090 static PRInt32
00091 FindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
00092 
00093   if(anOffset < 0)
00094     anOffset=0;
00095 
00096   if(aCount < 0)
00097     aCount = (PRInt32)aDestLength;
00098 
00099   if((aChar < 256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
00100 
00101     //We'll only search if the given aChar is within the normal ascii a range,
00102     //(Since this string is definitely within the ascii range).
00103     
00104     if(0<aCount) {
00105 
00106       const char* left= aDest+anOffset;
00107       const char* last= left+aCount;
00108       const char* max = aDest+aDestLength;
00109       const char* end = (last<max) ? last : max;
00110 
00111       PRInt32 theMax = end-left;
00112       if(0<theMax) {
00113         
00114         unsigned char theChar = (unsigned char) aChar;
00115         const char* result=(const char*)memchr(left, (int)theChar, theMax);
00116         
00117         if(result)
00118           return result-aDest;
00119         
00120       }
00121     }
00122   }
00123 
00124   return kNotFound;
00125 }
00126 
00127 
00139 static PRInt32
00140 FindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
00141 
00142   if(anOffset < 0)
00143     anOffset=0;
00144 
00145   if(aCount < 0)
00146     aCount = (PRInt32)aDestLength;
00147 
00148   if((0<aDestLength) && ((PRUint32)anOffset < aDestLength)) {
00149  
00150     if(0<aCount) {
00151 
00152       const PRUnichar* root = aDest;
00153       const PRUnichar* left = root+anOffset;
00154       const PRUnichar* last = left+aCount;
00155       const PRUnichar* max  = root+aDestLength;
00156       const PRUnichar* end  = (last<max) ? last : max;
00157 
00158       while(left<end){
00159         
00160         if(*left==aChar)
00161           return (left-root);
00162         
00163         ++left;
00164       }
00165     }
00166   }
00167 
00168   return kNotFound;
00169 }
00170 
00171 
00184 static PRInt32
00185 RFindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
00186 
00187   if(anOffset < 0)
00188     anOffset=(PRInt32)aDestLength-1;
00189 
00190   if(aCount < 0)
00191     aCount = PRInt32(aDestLength);
00192 
00193   if((aChar<256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
00194 
00195     //We'll only search if the given aChar is within the normal ascii a range,
00196     //(Since this string is definitely within the ascii range).
00197  
00198     if(0 < aCount) {
00199 
00200       const char* rightmost = aDest + anOffset;  
00201       const char* min       = rightmost - aCount + 1;
00202       const char* leftmost  = (min<aDest) ? aDest: min;
00203 
00204       char theChar=(char)aChar;
00205       while(leftmost <= rightmost){
00206         
00207         if((*rightmost) == theChar)
00208           return rightmost - aDest;
00209         
00210         --rightmost;
00211       }
00212     }
00213   }
00214 
00215   return kNotFound;
00216 }
00217 
00218 
00230 static PRInt32
00231 RFindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
00232 
00233   if(anOffset < 0)
00234     anOffset=(PRInt32)aDestLength-1;
00235 
00236   if(aCount < 0)
00237     aCount = PRInt32(aDestLength);
00238 
00239   if((0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
00240  
00241     if(0 < aCount) {
00242 
00243       const PRUnichar* root      = aDest;
00244       const PRUnichar* rightmost = root + anOffset;  
00245       const PRUnichar* min       = rightmost - aCount + 1;
00246       const PRUnichar* leftmost  = (min<root) ? root: min;
00247       
00248       while(leftmost <= rightmost){
00249         
00250         if((*rightmost) == aChar)
00251           return rightmost - root;
00252         
00253         --rightmost;
00254       }
00255     }
00256   }
00257 
00258   return kNotFound;
00259 }
00260 
00261 //-----------------------------------------------------------------------------
00262 //
00263 //  This set of methods is used to compare one buffer onto another.  The
00264 //  functions are differentiated by the size of source and dest character
00265 //  sizes.  WARNING: Your destination buffer MUST be big enough to hold all the
00266 //  source bytes.  We don't validate these ranges here (this should be done in
00267 //  higher level routines).
00268 //
00269 
00270 
00280 static
00281 #ifdef __SUNPRO_CC
00282 inline
00283 #endif /* __SUNPRO_CC */
00284 PRInt32
00285 Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ 
00286   PRInt32 result=0;
00287   if(aIgnoreCase)
00288     result=PRInt32(PL_strncasecmp(aStr1, aStr2, aCount));
00289   else 
00290     result=nsCharTraits<char>::compare(aStr1,aStr2,aCount);
00291 
00292       // alien comparisons may return out-of-bound answers
00293       //  instead of the -1, 0, 1 expected by most clients
00294   if ( result < -1 )
00295     result = -1;
00296   else if ( result > 1 )
00297     result = 1;
00298   return result;
00299 }
00300 
00310 static 
00311 #ifdef __SUNPRO_CC
00312 inline
00313 #endif /* __SUNPRO_CC */
00314 PRInt32
00315 Compare2To2(const PRUnichar* aStr1,const PRUnichar* aStr2,PRUint32 aCount){
00316   PRInt32 result;
00317   
00318   if ( aStr1 && aStr2 )
00319     result = nsCharTraits<PRUnichar>::compare(aStr1, aStr2, aCount);
00320 
00321       // The following cases are rare and survivable caller errors.
00322       //  Two null pointers are equal, but any string, even 0 length
00323       //  is greater than a null pointer.  It might not really matter,
00324       //  but we pick something reasonable anyway.
00325   else if ( !aStr1 && !aStr2 )
00326     result = 0;
00327   else if ( aStr1 )
00328     result = 1;
00329   else
00330     result = -1;
00331 
00332       // alien comparisons may give answers outside the -1, 0, 1 expected by callers
00333   if ( result < -1 )
00334     result = -1;
00335   else if ( result > 1 )
00336     result = 1;
00337   return result;
00338 }
00339 
00340 
00350 static
00351 #ifdef __SUNPRO_CC
00352 inline
00353 #endif /* __SUNPRO_CC */
00354 PRInt32
00355 Compare2To1(const PRUnichar* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
00356   const PRUnichar* s1 = aStr1;
00357   const char *s2 = aStr2;
00358   
00359   if (aStr1 && aStr2) {
00360     if (aCount != 0) {
00361       do {
00362 
00363         PRUnichar c1 = *s1++;
00364         PRUnichar c2 = PRUnichar((unsigned char)*s2++);
00365         
00366         if (c1 != c2) {
00367 #ifdef NS_DEBUG
00368           // we won't warn on c1>=128 (the 2-byte value) because often
00369           // it is just fine to compare an constant, ascii value (i.e. "body")
00370           // against some non-ascii value (i.e. a unicode string that
00371           // was downloaded from a web page)
00372           if (aIgnoreCase && c2>=128)
00373             NS_WARNING("got a non-ASCII string, but we can't do an accurate case conversion!");
00374 #endif
00375 
00376           // can't do case conversion on characters out of our range
00377           if (aIgnoreCase && c1<128 && c2<128) {
00378 
00379               c1 = ascii_tolower(char(c1));
00380               c2 = ascii_tolower(char(c2));
00381             
00382               if (c1 == c2) continue;
00383           }
00384 
00385           if (c1 < c2) return -1;
00386           return 1;
00387         }
00388       } while (--aCount);
00389     }
00390   }
00391   return 0;
00392 }
00393 
00394 
00404 inline PRInt32
00405 Compare1To2(const char* aStr1,const PRUnichar* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
00406   return Compare2To1(aStr2, aStr1, aCount, aIgnoreCase) * -1;
00407 }
00408 
00409 
00410 //-----------------------------------------------------------------------------
00411 //
00412 //  This set of methods is used compress char sequences in a buffer...
00413 //
00414 
00415 
00427 static PRInt32
00428 CompressChars1(char* aString,PRUint32 aLength,const char* aSet){ 
00429 
00430   char*  from = aString;
00431   char*  end =  aString + aLength;
00432   char*  to = from;
00433 
00434     //this code converts /n, /t, /r into normal space ' ';
00435     //it also compresses runs of whitespace down to a single char...
00436   if(aSet && aString && (0 < aLength)){
00437     PRUint32 aSetLen=strlen(aSet);
00438 
00439     while (from < end) {
00440       char theChar = *from++;
00441       
00442       *to++=theChar; //always copy this char...
00443 
00444       if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
00445         while (from < end) {
00446           theChar = *from++;
00447           if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
00448             *to++ = theChar;
00449             break;
00450           }
00451         } //while
00452       } //if
00453     } //if
00454     *to = 0;
00455   }
00456   return to - aString;
00457 }
00458 
00459 
00460 
00472 static PRInt32
00473 CompressChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){ 
00474 
00475   PRUnichar*  from = aString;
00476   PRUnichar*  end =  from + aLength;
00477   PRUnichar*  to = from;
00478 
00479     //this code converts /n, /t, /r into normal space ' ';
00480     //it also compresses runs of whitespace down to a single char...
00481   if(aSet && aString && (0 < aLength)){
00482     PRUint32 aSetLen=strlen(aSet);
00483 
00484     while (from < end) {
00485       PRUnichar theChar = *from++;
00486       
00487       *to++=theChar; //always copy this char...
00488 
00489       if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
00490         while (from < end) {
00491           theChar = *from++;
00492           if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
00493             *to++ = theChar;
00494             break;
00495           }
00496         } //while
00497       } //if
00498     } //if
00499     *to = 0;
00500   }
00501   return to - (PRUnichar*)aString;
00502 }
00503 
00515 static PRInt32
00516 StripChars1(char* aString,PRUint32 aLength,const char* aSet){ 
00517 
00518   // XXX(darin): this code should defer writing until necessary.
00519 
00520   char*  to   = aString;
00521   char*  from = aString-1;
00522   char*  end  = aString + aLength;
00523 
00524   if(aSet && aString && (0 < aLength)){
00525     PRUint32 aSetLen=strlen(aSet);
00526     while (++from < end) {
00527       char theChar = *from;
00528       if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
00529         *to++ = theChar;
00530       }
00531     }
00532     *to = 0;
00533   }
00534   return to - (char*)aString;
00535 }
00536 
00537 
00549 static PRInt32
00550 StripChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){ 
00551 
00552   // XXX(darin): this code should defer writing until necessary.
00553 
00554   PRUnichar*  to   = aString;
00555   PRUnichar*  from = aString-1;
00556   PRUnichar*  end  = to + aLength;
00557 
00558   if(aSet && aString && (0 < aLength)){
00559     PRUint32 aSetLen=strlen(aSet);
00560     while (++from < end) {
00561       PRUnichar theChar = *from;
00562       //Note the test for ascii range below. If you have a real unicode char, 
00563       //and you're searching for chars in the (given) ascii string, there's no
00564       //point in doing the real search since it's out of the ascii range.
00565       if((255<theChar) || (kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
00566         *to++ = theChar;
00567       }
00568     }
00569     *to = 0;
00570   }
00571   return to - (PRUnichar*)aString;
00572 }
00573 
00574 /* ***** END RICKG BLOCK ***** */
00575 
00576 static const char* kWhitespace="\b\t\r\n ";
00577 
00578 // This function is used to implement FindCharInSet and friends
00579 template <class CharT>
00580 #ifndef __SUNPRO_CC
00581 static
00582 #endif /* !__SUNPRO_CC */
00583 CharT
00584 GetFindInSetFilter( const CharT* set)
00585   {
00586     CharT filter = ~CharT(0); // All bits set
00587     while (*set) {
00588       filter &= ~(*set);
00589       ++set;
00590     }
00591     return filter;
00592   }
00593 
00594 // This template class is used by our code to access rickg's buffer routines.
00595 template <class CharT> struct nsBufferRoutines {};
00596 
00597 NS_SPECIALIZE_TEMPLATE
00598 struct nsBufferRoutines<char>
00599   {
00600     static
00601     PRInt32 compare( const char* a, const char* b, PRUint32 max, PRBool ic )
00602       {
00603         return Compare1To1(a, b, max, ic);
00604       }
00605 
00606     static
00607     PRInt32 compare( const char* a, const PRUnichar* b, PRUint32 max, PRBool ic )
00608       {
00609         return Compare1To2(a, b, max, ic);
00610       }
00611 
00612     static
00613     PRInt32 find_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
00614       {
00615         return FindChar1(s, max, offset, c, count);
00616       }
00617 
00618     static
00619     PRInt32 rfind_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
00620       {
00621         return RFindChar1(s, max, offset, c, count);
00622       }
00623 
00624     static
00625     char get_find_in_set_filter( const char* set )
00626       {
00627         return GetFindInSetFilter(set);
00628       }
00629 
00630     static
00631     PRInt32 strip_chars( char* s, PRUint32 len, const char* set )
00632       {
00633         return StripChars1(s, len, set);
00634       }
00635 
00636     static
00637     PRInt32 compress_chars( char* s, PRUint32 len, const char* set ) 
00638       {
00639         return CompressChars1(s, len, set);
00640       }
00641   };
00642 
00643 NS_SPECIALIZE_TEMPLATE
00644 struct nsBufferRoutines<PRUnichar>
00645   {
00646     static
00647     PRInt32 compare( const PRUnichar* a, const PRUnichar* b, PRUint32 max, PRBool ic )
00648       {
00649         NS_ASSERTION(!ic, "no case-insensitive compare here");
00650         return Compare2To2(a, b, max);
00651       }
00652 
00653     static
00654     PRInt32 compare( const PRUnichar* a, const char* b, PRUint32 max, PRBool ic )
00655       {
00656         return Compare2To1(a, b, max, ic);
00657       }
00658 
00659     static
00660     PRInt32 find_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
00661       {
00662         return FindChar2(s, max, offset, c, count);
00663       }
00664 
00665     static
00666     PRInt32 rfind_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
00667       {
00668         return RFindChar2(s, max, offset, c, count);
00669       }
00670 
00671     static
00672     PRUnichar get_find_in_set_filter( const PRUnichar* set )
00673       {
00674         return GetFindInSetFilter(set);
00675       }
00676 
00677     static
00678     PRUnichar get_find_in_set_filter( const char* set )
00679       {
00680         return (~PRUnichar(0)^~char(0)) | GetFindInSetFilter(set);
00681       }
00682 
00683     static
00684     PRInt32 strip_chars( PRUnichar* s, PRUint32 max, const char* set )
00685       {
00686         return StripChars2(s, max, set);
00687       }
00688 
00689     static
00690     PRInt32 compress_chars( PRUnichar* s, PRUint32 len, const char* set ) 
00691       {
00692         return CompressChars2(s, len, set);
00693       }
00694   };
00695 
00696 //-----------------------------------------------------------------------------
00697 
00698 template <class L, class R>
00699 #ifndef __SUNPRO_CC
00700 static
00701 #endif /* !__SUNPRO_CC */
00702 PRInt32
00703 FindSubstring( const L* big, PRUint32 bigLen,
00704                const R* little, PRUint32 littleLen,
00705                PRBool ignoreCase )
00706   {
00707     if (littleLen > bigLen)
00708       return kNotFound;
00709 
00710     PRInt32 i, max = PRInt32(bigLen - littleLen);
00711     for (i=0; i<=max; ++i, ++big)
00712       {
00713         if (nsBufferRoutines<L>::compare(big, little, littleLen, ignoreCase) == 0)
00714           return i;
00715       }
00716 
00717     return kNotFound;
00718   }
00719 
00720 template <class L, class R>
00721 #ifndef __SUNPRO_CC
00722 static
00723 #endif /* !__SUNPRO_CC */
00724 PRInt32
00725 RFindSubstring( const L* big, PRUint32 bigLen,
00726                 const R* little, PRUint32 littleLen,
00727                 PRBool ignoreCase )
00728   {
00729     if (littleLen > bigLen)
00730       return kNotFound;
00731 
00732     PRInt32 i, max = PRInt32(bigLen - littleLen);
00733 
00734     const L* iter = big + max;
00735     for (i=max; iter >= big; --i, --iter)
00736       {
00737         if (nsBufferRoutines<L>::compare(iter, little, littleLen, ignoreCase) == 0)
00738           return i;
00739       }
00740 
00741     return kNotFound;
00742   }
00743 
00744 template <class CharT, class SetCharT>
00745 #ifndef __SUNPRO_CC
00746 static
00747 #endif /* !__SUNPRO_CC */
00748 PRInt32
00749 FindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set )
00750   {
00751     CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set);
00752 
00753     const CharT* end = data + dataLen; 
00754     for (const CharT* iter = data; iter < end; ++iter)
00755       {
00756         CharT currentChar = *iter;
00757         if (currentChar & filter)
00758           continue; // char is not in filter set; go on with next char.
00759 
00760         // test all chars
00761         const SetCharT* charInSet = set;
00762         CharT setChar = CharT(*charInSet);
00763         while (setChar)
00764           {
00765             if (setChar == currentChar)
00766               return iter - data; // found it!  return index of the found char.
00767 
00768             setChar = CharT(*(++charInSet));
00769           }
00770       }
00771     return kNotFound;
00772   }
00773 
00774 template <class CharT, class SetCharT>
00775 #ifndef __SUNPRO_CC
00776 static
00777 #endif /* !__SUNPRO_CC */
00778 PRInt32
00779 RFindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set )
00780   {
00781     CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set);
00782 
00783     for (const CharT* iter = data + dataLen - 1; iter >= data; --iter)
00784       {
00785         CharT currentChar = *iter;
00786         if (currentChar & filter)
00787           continue; // char is not in filter set; go on with next char.
00788 
00789         // test all chars
00790         const CharT* charInSet = set;
00791         CharT setChar = *charInSet;
00792         while (setChar)
00793           {
00794             if (setChar == currentChar)
00795               return iter - data; // found it!  return index of the found char.
00796 
00797             setChar = *(++charInSet);
00798           }
00799       }
00800     return kNotFound;
00801   }
00802 
00809 void 
00810 Modified_cnvtf(char *buf, int bufsz, int prcsn, double fval)
00811 {
00812   PRIntn decpt, sign, numdigits;
00813   char *num, *nump;
00814   char *bufp = buf;
00815   char *endnum;
00816 
00817   /* If anything fails, we store an empty string in 'buf' */
00818   num = (char*)malloc(bufsz);
00819   if (num == NULL) {
00820     buf[0] = '\0';
00821     return;
00822   }
00823   if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, bufsz)
00824       == PR_FAILURE) {
00825     buf[0] = '\0';
00826     goto done;
00827   }
00828   numdigits = endnum - num;
00829   nump = num;
00830 
00831   /*
00832    * The NSPR code had a fancy way of checking that we weren't dealing
00833    * with -0.0 or -NaN, but I'll just use < instead.
00834    * XXX Should we check !isnan(fval) as well?  Is it portable?  We
00835    * probably don't need to bother since NAN isn't portable.
00836    */
00837   if (sign && fval < 0.0f) {
00838     *bufp++ = '-';
00839   }
00840 
00841   if (decpt == 9999) {
00842     while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */
00843     goto done;
00844   }
00845 
00846   if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) {
00847     *bufp++ = *nump++;
00848     if (numdigits != 1) {
00849       *bufp++ = '.';
00850     }
00851 
00852     while (*nump != '\0') {
00853       *bufp++ = *nump++;
00854     }
00855     *bufp++ = 'e';
00856     PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1);
00857   }
00858   else if (decpt >= 0) {
00859     if (decpt == 0) {
00860       *bufp++ = '0';
00861     }
00862     else {
00863       while (decpt--) {
00864         if (*nump != '\0') {
00865           *bufp++ = *nump++;
00866         }
00867         else {
00868           *bufp++ = '0';
00869         }
00870       }
00871     }
00872     if (*nump != '\0') {
00873       *bufp++ = '.';
00874       while (*nump != '\0') {
00875         *bufp++ = *nump++;
00876       }
00877     }
00878     *bufp++ = '\0';
00879   }
00880   else if (decpt < 0) {
00881     *bufp++ = '0';
00882     *bufp++ = '.';
00883     while (decpt++) {
00884       *bufp++ = '0';
00885     }
00886 
00887     while (*nump != '\0') {
00888       *bufp++ = *nump++;
00889     }
00890     *bufp++ = '\0';
00891   }
00892 done:
00893   free(num);
00894 }
00895 
00903 static void
00904 Find_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count )
00905   {
00906     // |count| specifies how many iterations to make from |offset|
00907 
00908     if (offset < 0)
00909       {
00910         offset = 0;
00911       }
00912     else if (PRUint32(offset) > bigLen)
00913       {
00914         count = 0;
00915         return;
00916       }
00917 
00918     PRInt32 maxCount = bigLen - offset;
00919     if (count < 0 || count > maxCount)
00920       {
00921         count = maxCount;
00922       } 
00923     else
00924       {
00925         count += littleLen;
00926         if (count > maxCount)
00927           count = maxCount;
00928       }
00929   }
00930 
00955 static void
00956 RFind_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count )
00957   {
00958     if (littleLen > bigLen)
00959       {
00960         offset = 0;
00961         count = 0;
00962         return;
00963       }
00964 
00965     if (offset < 0)
00966       offset = bigLen - littleLen;
00967     if (count < 0)
00968       count = offset + 1;
00969 
00970     PRInt32 start = offset - count + 1;
00971     if (start < 0)
00972       start = 0;
00973 
00974     count = offset + littleLen - start;
00975     offset = start;
00976   }
00977 
00978 //-----------------------------------------------------------------------------
00979 
00980   // define nsString obsolete methods
00981 #include "string-template-def-unichar.h"
00982 #include "nsTStringObsolete.cpp"
00983 #include "string-template-undef.h"
00984 
00985   // define nsCString obsolete methods
00986 #include "string-template-def-char.h"
00987 #include "nsTStringObsolete.cpp"
00988 #include "string-template-undef.h"
00989 
00990 //-----------------------------------------------------------------------------
00991 
00992 // specialized methods:
00993 
00994 PRInt32
00995 nsString::Find( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const
00996   {
00997     // this method changes the meaning of aOffset and aCount:
00998     Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
00999 
01000     PRInt32 result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE);
01001     if (result != kNotFound)
01002       result += aOffset;
01003     return result;
01004   }
01005 
01006 PRInt32
01007 nsString::Find( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const
01008   {
01009     return Find(nsDependentString(aString), aOffset, aCount);
01010   }
01011 
01012 PRInt32
01013 nsString::RFind( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const
01014   {
01015     // this method changes the meaning of aOffset and aCount:
01016     RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
01017 
01018     PRInt32 result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE);
01019     if (result != kNotFound)
01020       result += aOffset;
01021     return result;
01022   }
01023 
01024 PRInt32
01025 nsString::RFind( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const
01026   {
01027     return RFind(nsDependentString(aString), aOffset, aCount);
01028   }
01029 
01030 PRInt32
01031 nsString::FindCharInSet( const PRUnichar* aSet, PRInt32 aOffset ) const
01032   {
01033     if (aOffset < 0)
01034       aOffset = 0;
01035     else if (aOffset >= PRInt32(mLength))
01036       return kNotFound;
01037     
01038     PRInt32 result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet);
01039     if (result != kNotFound)
01040       result += aOffset;
01041     return result;
01042   }
01043 
01044 
01049 PRInt32
01050 nsCString::Compare( const char* aString, PRBool aIgnoreCase, PRInt32 aCount ) const
01051   {
01052     PRUint32 strLen = char_traits::length(aString);
01053 
01054     PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen));
01055 
01056     PRInt32 compareCount;
01057     if (aCount < 0 || aCount > maxCount)
01058       compareCount = maxCount;
01059     else
01060       compareCount = aCount;
01061 
01062     PRInt32 result =
01063         nsBufferRoutines<char>::compare(mData, aString, compareCount, aIgnoreCase);
01064 
01065     if (result == 0 &&
01066           (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount)))
01067       {
01068         // Since the caller didn't give us a length to test, or strings shorter
01069         // than aCount, and compareCount characters matched, we have to assume
01070         // that the longer string is greater.
01071 
01072         if (mLength != strLen)
01073           result = (mLength < strLen) ? -1 : 1;
01074       }
01075     return result;
01076   }
01077 
01078 PRBool
01079 nsString::EqualsIgnoreCase( const char* aString, PRInt32 aCount ) const
01080   {
01081     PRUint32 strLen = nsCharTraits<char>::length(aString);
01082 
01083     PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen));
01084 
01085     PRInt32 compareCount;
01086     if (aCount < 0 || aCount > maxCount)
01087       compareCount = maxCount;
01088     else
01089       compareCount = aCount;
01090 
01091     PRInt32 result =
01092         nsBufferRoutines<PRUnichar>::compare(mData, aString, compareCount, PR_TRUE);
01093 
01094     if (result == 0 &&
01095           (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount)))
01096       {
01097         // Since the caller didn't give us a length to test, or strings shorter
01098         // than aCount, and compareCount characters matched, we have to assume
01099         // that the longer string is greater.
01100 
01101         if (mLength != strLen)
01102           result = 1; // Arbitrarily using any number != 0
01103       }
01104     return result == 0;
01105   }
01106 
01111 char*
01112 nsString::ToCString( char* aBuf, PRUint32 aBufLength, PRUint32 aOffset ) const
01113   {
01114       // because the old implementation checked aBuf
01115     if (!(aBuf && aBufLength > 0 && aOffset <= mLength))
01116       return nsnull;
01117 
01118     PRUint32 maxCount = NS_MIN(aBufLength-1, mLength - aOffset);
01119 
01120     LossyConvertEncoding<PRUnichar, char> converter(aBuf);
01121     converter.write(mData + aOffset, maxCount);
01122     converter.write_terminator();
01123     return aBuf;
01124   }
01125 
01126 float
01127 nsCString::ToFloat(PRInt32* aErrorCode) const
01128   {
01129     float res = 0.0f;
01130     if (mLength > 0)
01131       {
01132         char *conv_stopped;
01133         const char *str = mData;
01134         // Use PR_strtod, not strtod, since we don't want locale involved.
01135         res = (float)PR_strtod(str, &conv_stopped);
01136         if (conv_stopped == str+mLength)
01137           *aErrorCode = (PRInt32) NS_OK;
01138         else // Not all the string was scanned
01139           *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
01140       }
01141     else
01142       {
01143         // The string was too short (0 characters)
01144         *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
01145       }
01146     return res;
01147   }
01148 
01149 float
01150 nsString::ToFloat(PRInt32* aErrorCode) const
01151   {
01152     float res = 0.0f;
01153     char buf[100];
01154     if (mLength > 0 && mLength < sizeof(buf))
01155       {
01156         char *conv_stopped;
01157         const char *str = ToCString(buf, sizeof(buf));
01158         // Use PR_strtod, not strtod, since we don't want locale involved.
01159         res = (float)PR_strtod(str, &conv_stopped);
01160         if (conv_stopped == str+mLength)
01161           *aErrorCode = (PRInt32) NS_OK;
01162         else // Not all the string was scanned
01163           *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
01164       }
01165     else
01166       {
01167         // The string was too short (0 characters) or too long (sizeof(buf))
01168         *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
01169       }
01170     return res;
01171   }
01172 
01173 
01178 void
01179 nsCString::AssignWithConversion( const nsAString& aData )
01180   {
01181     LossyCopyUTF16toASCII(aData, *this);
01182   }
01183 
01184 void
01185 nsString::AssignWithConversion( const nsACString& aData )
01186   {
01187     CopyASCIItoUTF16(aData, *this);
01188   }
01189 
01190 
01195 void
01196 nsCString::AppendWithConversion( const nsAString& aData )
01197   {
01198     LossyAppendUTF16toASCII(aData, *this);
01199   }
01200 
01201 void
01202 nsString::AppendWithConversion( const nsACString& aData )
01203   {
01204     AppendASCIItoUTF16(aData, *this);
01205   }
01206 
01207 
01212 void
01213 nsCString::AppendInt( PRInt32 aInteger, PRInt32 aRadix )
01214   {
01215     char buf[20];
01216     const char* fmt;
01217     switch (aRadix) {
01218       case 8:
01219         fmt = "%o";
01220         break;
01221       case 10:
01222         fmt = "%d";
01223         break;
01224       default:
01225         NS_ASSERTION(aRadix == 16, "Invalid radix!");
01226         fmt = "%x";
01227     }
01228     PR_snprintf(buf, sizeof(buf), fmt, aInteger);
01229     Append(buf);
01230   }
01231 
01232 void
01233 nsString::AppendInt( PRInt32 aInteger, PRInt32 aRadix )
01234   {
01235     char buf[20];
01236     const char* fmt;
01237     switch (aRadix) {
01238       case 8:
01239         fmt = "%o";
01240         break;
01241       case 10:
01242         fmt = "%d";
01243         break;
01244       default:
01245         NS_ASSERTION(aRadix == 16, "Invalid radix!");
01246         fmt = "%x";
01247     }
01248     PR_snprintf(buf, sizeof(buf), fmt, aInteger);
01249     AppendASCIItoUTF16(buf, *this);
01250   }
01251 
01252 void
01253 nsCString::AppendInt( PRInt64 aInteger, PRInt32 aRadix )
01254   {
01255     char buf[30];
01256     const char* fmt;
01257     switch (aRadix) {
01258       case 8:
01259         fmt = "%llo";
01260         break;
01261       case 10:
01262         fmt = "%lld";
01263         break;
01264       default:
01265         NS_ASSERTION(aRadix == 16, "Invalid radix!");
01266         fmt = "%llx";
01267     }
01268     PR_snprintf(buf, sizeof(buf), fmt, aInteger);
01269     Append(buf);
01270   }
01271 
01272 void
01273 nsString::AppendInt( PRInt64 aInteger, PRInt32 aRadix )
01274   {
01275     char buf[30];
01276     const char* fmt;
01277     switch (aRadix) {
01278       case 8:
01279         fmt = "%llo";
01280         break;
01281       case 10:
01282         fmt = "%lld";
01283         break;
01284       default:
01285         NS_ASSERTION(aRadix == 16, "Invalid radix!");
01286         fmt = "%llx";
01287     }
01288     PR_snprintf(buf, sizeof(buf), fmt, aInteger);
01289     AppendASCIItoUTF16(buf, *this);
01290   }
01291 
01296 void
01297 nsCString::AppendFloat( double aFloat )
01298   {
01299     char buf[40];
01300     // Use Modified_cnvtf, which is locale-insensitive, instead of the
01301     // locale-sensitive PR_snprintf or sprintf(3)
01302     Modified_cnvtf(buf, sizeof(buf), 6, aFloat);
01303     Append(buf);
01304   }
01305 
01306 void
01307 nsString::AppendFloat( double aFloat )
01308   {
01309     char buf[40];
01310     // Use Modified_cnvtf, which is locale-insensitive, instead of the
01311     // locale-sensitive PR_snprintf or sprintf(3)
01312     Modified_cnvtf(buf, sizeof(buf), 6, aFloat);
01313     AppendWithConversion(buf);
01314   }
01315 
01316 #endif // !MOZ_STRING_WITH_OBSOLETE_API