Bug 452317 - FeedConverter.js: QueryInterface should throw NS_ERROR_NO_INTERFACE...
[wine-gecko.git] / xpcom / string / src / nsStringObsolete.cpp
blob9dd13d7e6a7367dc678ed41992d0638beec83ab0
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla.
18 * The Initial Developer of the Original Code is IBM Corporation.
19 * Portions created by IBM Corporation are Copyright (C) 2003
20 * IBM Corporation. All Rights Reserved.
22 * Contributor(s):
23 * Darin Fisher <darin@meer.net>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsString.h"
42 /**
43 * nsTString obsolete API support
46 #if MOZ_STRING_WITH_OBSOLETE_API
48 #include "nsDependentString.h"
49 #include "nsDependentSubstring.h"
50 #include "nsReadableUtils.h"
51 #include "nsCRT.h"
52 #include "nsUTF8Utils.h"
53 #include "prdtoa.h"
54 #include "prprf.h"
56 /* ***** BEGIN RICKG BLOCK *****
58 * NOTE: This section of code was extracted from rickg's bufferRoutines.h file.
59 * For the most part it remains unmodified. We want to eliminate (or at
60 * least clean up) this code at some point. If you find the formatting
61 * in this section somewhat inconsistent, don't blame me! ;-)
64 // avoid STDC's tolower since it may do weird things with non-ASCII bytes
65 inline char
66 ascii_tolower(char aChar)
68 if (aChar >= 'A' && aChar <= 'Z')
69 return aChar + ('a' - 'A');
70 return aChar;
73 //-----------------------------------------------------------------------------
75 // This set of methods is used to search a buffer looking for a char.
79 /**
80 * This methods cans the given buffer for the given char
82 * @update gess 02/17/00
83 * @param aDest is the buffer to be searched
84 * @param aDestLength is the size (in char-units, not bytes) of the buffer
85 * @param anOffset is the start pos to begin searching
86 * @param aChar is the target character we're looking for
87 * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
88 * @return index of pos if found, else -1 (kNotFound)
90 static PRInt32
91 FindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
93 if(anOffset < 0)
94 anOffset=0;
96 if(aCount < 0)
97 aCount = (PRInt32)aDestLength;
99 if((aChar < 256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
101 //We'll only search if the given aChar is within the normal ascii a range,
102 //(Since this string is definitely within the ascii range).
104 if(0<aCount) {
106 const char* left= aDest+anOffset;
107 const char* last= left+aCount;
108 const char* max = aDest+aDestLength;
109 const char* end = (last<max) ? last : max;
111 PRInt32 theMax = end-left;
112 if(0<theMax) {
114 unsigned char theChar = (unsigned char) aChar;
115 const char* result=(const char*)memchr(left, (int)theChar, theMax);
117 if(result)
118 return result-aDest;
124 return kNotFound;
129 * This methods cans the given buffer for the given char
131 * @update gess 3/25/98
132 * @param aDest is the buffer to be searched
133 * @param aDestLength is the size (in char-units, not bytes) of the buffer
134 * @param anOffset is the start pos to begin searching
135 * @param aChar is the target character we're looking for
136 * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
137 * @return index of pos if found, else -1 (kNotFound)
139 static PRInt32
140 FindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
142 if(anOffset < 0)
143 anOffset=0;
145 if(aCount < 0)
146 aCount = (PRInt32)aDestLength;
148 if((0<aDestLength) && ((PRUint32)anOffset < aDestLength)) {
150 if(0<aCount) {
152 const PRUnichar* root = aDest;
153 const PRUnichar* left = root+anOffset;
154 const PRUnichar* last = left+aCount;
155 const PRUnichar* max = root+aDestLength;
156 const PRUnichar* end = (last<max) ? last : max;
158 while(left<end){
160 if(*left==aChar)
161 return (left-root);
163 ++left;
168 return kNotFound;
173 * This methods cans the given buffer (in reverse) for the given char
175 * @update gess 02/17/00
176 * @param aDest is the buffer to be searched
177 * @param aDestLength is the size (in char-units, not bytes) of the buffer
178 * @param anOffset is the start pos to begin searching
179 * @param aChar is the target character we're looking for
180 * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
181 * @return index of pos if found, else -1 (kNotFound)
184 static PRInt32
185 RFindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
187 if(anOffset < 0)
188 anOffset=(PRInt32)aDestLength-1;
190 if(aCount < 0)
191 aCount = PRInt32(aDestLength);
193 if((aChar<256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
195 //We'll only search if the given aChar is within the normal ascii a range,
196 //(Since this string is definitely within the ascii range).
198 if(0 < aCount) {
200 const char* rightmost = aDest + anOffset;
201 const char* min = rightmost - aCount + 1;
202 const char* leftmost = (min<aDest) ? aDest: min;
204 char theChar=(char)aChar;
205 while(leftmost <= rightmost){
207 if((*rightmost) == theChar)
208 return rightmost - aDest;
210 --rightmost;
215 return kNotFound;
220 * This methods cans the given buffer for the given char
222 * @update gess 3/25/98
223 * @param aDest is the buffer to be searched
224 * @param aDestLength is the size (in char-units, not bytes) of the buffer
225 * @param anOffset is the start pos to begin searching
226 * @param aChar is the target character we're looking for
227 * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
228 * @return index of pos if found, else -1 (kNotFound)
230 static PRInt32
231 RFindChar2(const PRUnichar* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) {
233 if(anOffset < 0)
234 anOffset=(PRInt32)aDestLength-1;
236 if(aCount < 0)
237 aCount = PRInt32(aDestLength);
239 if((0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) {
241 if(0 < aCount) {
243 const PRUnichar* root = aDest;
244 const PRUnichar* rightmost = root + anOffset;
245 const PRUnichar* min = rightmost - aCount + 1;
246 const PRUnichar* leftmost = (min<root) ? root: min;
248 while(leftmost <= rightmost){
250 if((*rightmost) == aChar)
251 return rightmost - root;
253 --rightmost;
258 return kNotFound;
261 //-----------------------------------------------------------------------------
263 // This set of methods is used to compare one buffer onto another. The
264 // functions are differentiated by the size of source and dest character
265 // sizes. WARNING: Your destination buffer MUST be big enough to hold all the
266 // source bytes. We don't validate these ranges here (this should be done in
267 // higher level routines).
272 * This method compares the data in one buffer with another
273 * @update gess 01/04/99
274 * @param aStr1 is the first buffer to be compared
275 * @param aStr2 is the 2nd buffer to be compared
276 * @param aCount is the number of chars to compare
277 * @param aIgnoreCase tells us whether to use a case-sensitive comparison
278 * @return -1,0,1 depending on <,==,>
280 static
281 #ifdef __SUNPRO_CC
282 inline
283 #endif /* __SUNPRO_CC */
284 PRInt32
285 Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
286 PRInt32 result=0;
287 if(aIgnoreCase)
288 result=PRInt32(PL_strncasecmp(aStr1, aStr2, aCount));
289 else
290 result=nsCharTraits<char>::compare(aStr1,aStr2,aCount);
292 // alien comparisons may return out-of-bound answers
293 // instead of the -1, 0, 1 expected by most clients
294 if ( result < -1 )
295 result = -1;
296 else if ( result > 1 )
297 result = 1;
298 return result;
302 * This method compares the data in one buffer with another
303 * @update gess 01/04/99
304 * @param aStr1 is the first buffer to be compared
305 * @param aStr2 is the 2nd buffer to be compared
306 * @param aCount is the number of chars to compare
307 * @param aIgnoreCase tells us whether to use a case-sensitive comparison
308 * @return -1,0,1 depending on <,==,>
310 static
311 #ifdef __SUNPRO_CC
312 inline
313 #endif /* __SUNPRO_CC */
314 PRInt32
315 Compare2To2(const PRUnichar* aStr1,const PRUnichar* aStr2,PRUint32 aCount){
316 PRInt32 result;
318 if ( aStr1 && aStr2 )
319 result = nsCharTraits<PRUnichar>::compare(aStr1, aStr2, aCount);
321 // The following cases are rare and survivable caller errors.
322 // Two null pointers are equal, but any string, even 0 length
323 // is greater than a null pointer. It might not really matter,
324 // but we pick something reasonable anyway.
325 else if ( !aStr1 && !aStr2 )
326 result = 0;
327 else if ( aStr1 )
328 result = 1;
329 else
330 result = -1;
332 // alien comparisons may give answers outside the -1, 0, 1 expected by callers
333 if ( result < -1 )
334 result = -1;
335 else if ( result > 1 )
336 result = 1;
337 return result;
342 * This method compares the data in one buffer with another
343 * @update gess 01/04/99
344 * @param aStr1 is the first buffer to be compared
345 * @param aStr2 is the 2nd buffer to be compared
346 * @param aCount is the number of chars to compare
347 * @param aIgnoreCase tells us whether to use a case-sensitive comparison
348 * @return -1,0,1 depending on <,==,>
350 static
351 #ifdef __SUNPRO_CC
352 inline
353 #endif /* __SUNPRO_CC */
354 PRInt32
355 Compare2To1(const PRUnichar* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
356 const PRUnichar* s1 = aStr1;
357 const char *s2 = aStr2;
359 if (aStr1 && aStr2) {
360 if (aCount != 0) {
361 do {
363 PRUnichar c1 = *s1++;
364 PRUnichar c2 = PRUnichar((unsigned char)*s2++);
366 if (c1 != c2) {
367 #ifdef NS_DEBUG
368 // we won't warn on c1>=128 (the 2-byte value) because often
369 // it is just fine to compare an constant, ascii value (i.e. "body")
370 // against some non-ascii value (i.e. a unicode string that
371 // was downloaded from a web page)
372 if (aIgnoreCase && c2>=128)
373 NS_WARNING("got a non-ASCII string, but we can't do an accurate case conversion!");
374 #endif
376 // can't do case conversion on characters out of our range
377 if (aIgnoreCase && c1<128 && c2<128) {
379 c1 = ascii_tolower(char(c1));
380 c2 = ascii_tolower(char(c2));
382 if (c1 == c2) continue;
385 if (c1 < c2) return -1;
386 return 1;
388 } while (--aCount);
391 return 0;
396 * This method compares the data in one buffer with another
397 * @update gess 01/04/99
398 * @param aStr1 is the first buffer to be compared
399 * @param aStr2 is the 2nd buffer to be compared
400 * @param aCount is the number of chars to compare
401 * @param aIgnoreCase tells us whether to use a case-sensitive comparison
402 * @return -1,0,1 depending on <,==,>
404 inline PRInt32
405 Compare1To2(const char* aStr1,const PRUnichar* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
406 return Compare2To1(aStr2, aStr1, aCount, aIgnoreCase) * -1;
410 //-----------------------------------------------------------------------------
412 // This set of methods is used compress char sequences in a buffer...
417 * This method compresses duplicate runs of a given char from the given buffer
419 * @update rickg 03.23.2000
420 * @param aString is the buffer to be manipulated
421 * @param aLength is the length of the buffer
422 * @param aSet tells us which chars to compress from given buffer
423 * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
424 * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
425 * @return the new length of the given buffer
427 static PRInt32
428 CompressChars1(char* aString,PRUint32 aLength,const char* aSet){
430 char* from = aString;
431 char* end = aString + aLength;
432 char* to = from;
434 //this code converts /n, /t, /r into normal space ' ';
435 //it also compresses runs of whitespace down to a single char...
436 if(aSet && aString && (0 < aLength)){
437 PRUint32 aSetLen=strlen(aSet);
439 while (from < end) {
440 char theChar = *from++;
442 *to++=theChar; //always copy this char...
444 if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
445 while (from < end) {
446 theChar = *from++;
447 if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
448 *to++ = theChar;
449 break;
451 } //while
452 } //if
453 } //if
454 *to = 0;
456 return to - aString;
462 * This method compresses duplicate runs of a given char from the given buffer
464 * @update rickg 03.23.2000
465 * @param aString is the buffer to be manipulated
466 * @param aLength is the length of the buffer
467 * @param aSet tells us which chars to compress from given buffer
468 * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
469 * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
470 * @return the new length of the given buffer
472 static PRInt32
473 CompressChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){
475 PRUnichar* from = aString;
476 PRUnichar* end = from + aLength;
477 PRUnichar* to = from;
479 //this code converts /n, /t, /r into normal space ' ';
480 //it also compresses runs of whitespace down to a single char...
481 if(aSet && aString && (0 < aLength)){
482 PRUint32 aSetLen=strlen(aSet);
484 while (from < end) {
485 PRUnichar theChar = *from++;
487 *to++=theChar; //always copy this char...
489 if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
490 while (from < end) {
491 theChar = *from++;
492 if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
493 *to++ = theChar;
494 break;
496 } //while
497 } //if
498 } //if
499 *to = 0;
501 return to - (PRUnichar*)aString;
505 * This method strips chars in a given set from the given buffer
507 * @update gess 01/04/99
508 * @param aString is the buffer to be manipulated
509 * @param aLength is the length of the buffer
510 * @param aSet tells us which chars to compress from given buffer
511 * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
512 * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
513 * @return the new length of the given buffer
515 static PRInt32
516 StripChars1(char* aString,PRUint32 aLength,const char* aSet){
518 // XXX(darin): this code should defer writing until necessary.
520 char* to = aString;
521 char* from = aString-1;
522 char* end = aString + aLength;
524 if(aSet && aString && (0 < aLength)){
525 PRUint32 aSetLen=strlen(aSet);
526 while (++from < end) {
527 char theChar = *from;
528 if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){
529 *to++ = theChar;
532 *to = 0;
534 return to - (char*)aString;
539 * This method strips chars in a given set from the given buffer
541 * @update gess 01/04/99
542 * @param aString is the buffer to be manipulated
543 * @param aLength is the length of the buffer
544 * @param aSet tells us which chars to compress from given buffer
545 * @param aEliminateLeading tells us whether to strip chars from the start of the buffer
546 * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
547 * @return the new length of the given buffer
549 static PRInt32
550 StripChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){
552 // XXX(darin): this code should defer writing until necessary.
554 PRUnichar* to = aString;
555 PRUnichar* from = aString-1;
556 PRUnichar* end = to + aLength;
558 if(aSet && aString && (0 < aLength)){
559 PRUint32 aSetLen=strlen(aSet);
560 while (++from < end) {
561 PRUnichar theChar = *from;
562 //Note the test for ascii range below. If you have a real unicode char,
563 //and you're searching for chars in the (given) ascii string, there's no
564 //point in doing the real search since it's out of the ascii range.
565 if((255<theChar) || (kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen))){
566 *to++ = theChar;
569 *to = 0;
571 return to - (PRUnichar*)aString;
574 /* ***** END RICKG BLOCK ***** */
576 static const char* kWhitespace="\b\t\r\n ";
578 // This function is used to implement FindCharInSet and friends
579 template <class CharT>
580 #ifndef __SUNPRO_CC
581 static
582 #endif /* !__SUNPRO_CC */
583 CharT
584 GetFindInSetFilter( const CharT* set)
586 CharT filter = ~CharT(0); // All bits set
587 while (*set) {
588 filter &= ~(*set);
589 ++set;
591 return filter;
594 // This template class is used by our code to access rickg's buffer routines.
595 template <class CharT> struct nsBufferRoutines {};
597 NS_SPECIALIZE_TEMPLATE
598 struct nsBufferRoutines<char>
600 static
601 PRInt32 compare( const char* a, const char* b, PRUint32 max, PRBool ic )
603 return Compare1To1(a, b, max, ic);
606 static
607 PRInt32 compare( const char* a, const PRUnichar* b, PRUint32 max, PRBool ic )
609 return Compare1To2(a, b, max, ic);
612 static
613 PRInt32 find_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
615 return FindChar1(s, max, offset, c, count);
618 static
619 PRInt32 rfind_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
621 return RFindChar1(s, max, offset, c, count);
624 static
625 char get_find_in_set_filter( const char* set )
627 return GetFindInSetFilter(set);
630 static
631 PRInt32 strip_chars( char* s, PRUint32 len, const char* set )
633 return StripChars1(s, len, set);
636 static
637 PRInt32 compress_chars( char* s, PRUint32 len, const char* set )
639 return CompressChars1(s, len, set);
643 NS_SPECIALIZE_TEMPLATE
644 struct nsBufferRoutines<PRUnichar>
646 static
647 PRInt32 compare( const PRUnichar* a, const PRUnichar* b, PRUint32 max, PRBool ic )
649 NS_ASSERTION(!ic, "no case-insensitive compare here");
650 return Compare2To2(a, b, max);
653 static
654 PRInt32 compare( const PRUnichar* a, const char* b, PRUint32 max, PRBool ic )
656 return Compare2To1(a, b, max, ic);
659 static
660 PRInt32 find_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
662 return FindChar2(s, max, offset, c, count);
665 static
666 PRInt32 rfind_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count )
668 return RFindChar2(s, max, offset, c, count);
671 static
672 PRUnichar get_find_in_set_filter( const PRUnichar* set )
674 return GetFindInSetFilter(set);
677 static
678 PRUnichar get_find_in_set_filter( const char* set )
680 return (~PRUnichar(0)^~char(0)) | GetFindInSetFilter(set);
683 static
684 PRInt32 strip_chars( PRUnichar* s, PRUint32 max, const char* set )
686 return StripChars2(s, max, set);
689 static
690 PRInt32 compress_chars( PRUnichar* s, PRUint32 len, const char* set )
692 return CompressChars2(s, len, set);
696 //-----------------------------------------------------------------------------
698 template <class L, class R>
699 #ifndef __SUNPRO_CC
700 static
701 #endif /* !__SUNPRO_CC */
702 PRInt32
703 FindSubstring( const L* big, PRUint32 bigLen,
704 const R* little, PRUint32 littleLen,
705 PRBool ignoreCase )
707 if (littleLen > bigLen)
708 return kNotFound;
710 PRInt32 i, max = PRInt32(bigLen - littleLen);
711 for (i=0; i<=max; ++i, ++big)
713 if (nsBufferRoutines<L>::compare(big, little, littleLen, ignoreCase) == 0)
714 return i;
717 return kNotFound;
720 template <class L, class R>
721 #ifndef __SUNPRO_CC
722 static
723 #endif /* !__SUNPRO_CC */
724 PRInt32
725 RFindSubstring( const L* big, PRUint32 bigLen,
726 const R* little, PRUint32 littleLen,
727 PRBool ignoreCase )
729 if (littleLen > bigLen)
730 return kNotFound;
732 PRInt32 i, max = PRInt32(bigLen - littleLen);
734 const L* iter = big + max;
735 for (i=max; iter >= big; --i, --iter)
737 if (nsBufferRoutines<L>::compare(iter, little, littleLen, ignoreCase) == 0)
738 return i;
741 return kNotFound;
744 template <class CharT, class SetCharT>
745 #ifndef __SUNPRO_CC
746 static
747 #endif /* !__SUNPRO_CC */
748 PRInt32
749 FindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set )
751 CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set);
753 const CharT* end = data + dataLen;
754 for (const CharT* iter = data; iter < end; ++iter)
756 CharT currentChar = *iter;
757 if (currentChar & filter)
758 continue; // char is not in filter set; go on with next char.
760 // test all chars
761 const SetCharT* charInSet = set;
762 CharT setChar = CharT(*charInSet);
763 while (setChar)
765 if (setChar == currentChar)
766 return iter - data; // found it! return index of the found char.
768 setChar = CharT(*(++charInSet));
771 return kNotFound;
774 template <class CharT, class SetCharT>
775 #ifndef __SUNPRO_CC
776 static
777 #endif /* !__SUNPRO_CC */
778 PRInt32
779 RFindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set )
781 CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set);
783 for (const CharT* iter = data + dataLen - 1; iter >= data; --iter)
785 CharT currentChar = *iter;
786 if (currentChar & filter)
787 continue; // char is not in filter set; go on with next char.
789 // test all chars
790 const CharT* charInSet = set;
791 CharT setChar = *charInSet;
792 while (setChar)
794 if (setChar == currentChar)
795 return iter - data; // found it! return index of the found char.
797 setChar = *(++charInSet);
800 return kNotFound;
804 * This is a copy of |PR_cnvtf| with a bug fixed. (The second argument
805 * of PR_dtoa is 2 rather than 1.)
807 * XXX(darin): if this is the right thing, then why wasn't it fixed in NSPR?!?
809 void
810 Modified_cnvtf(char *buf, int bufsz, int prcsn, double fval)
812 PRIntn decpt, sign, numdigits;
813 char *num, *nump;
814 char *bufp = buf;
815 char *endnum;
817 /* If anything fails, we store an empty string in 'buf' */
818 num = (char*)malloc(bufsz);
819 if (num == NULL) {
820 buf[0] = '\0';
821 return;
823 if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, bufsz)
824 == PR_FAILURE) {
825 buf[0] = '\0';
826 goto done;
828 numdigits = endnum - num;
829 nump = num;
832 * The NSPR code had a fancy way of checking that we weren't dealing
833 * with -0.0 or -NaN, but I'll just use < instead.
834 * XXX Should we check !isnan(fval) as well? Is it portable? We
835 * probably don't need to bother since NAN isn't portable.
837 if (sign && fval < 0.0f) {
838 *bufp++ = '-';
841 if (decpt == 9999) {
842 while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */
843 goto done;
846 if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) {
847 *bufp++ = *nump++;
848 if (numdigits != 1) {
849 *bufp++ = '.';
852 while (*nump != '\0') {
853 *bufp++ = *nump++;
855 *bufp++ = 'e';
856 PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1);
858 else if (decpt >= 0) {
859 if (decpt == 0) {
860 *bufp++ = '0';
862 else {
863 while (decpt--) {
864 if (*nump != '\0') {
865 *bufp++ = *nump++;
867 else {
868 *bufp++ = '0';
872 if (*nump != '\0') {
873 *bufp++ = '.';
874 while (*nump != '\0') {
875 *bufp++ = *nump++;
878 *bufp++ = '\0';
880 else if (decpt < 0) {
881 *bufp++ = '0';
882 *bufp++ = '.';
883 while (decpt++) {
884 *bufp++ = '0';
887 while (*nump != '\0') {
888 *bufp++ = *nump++;
890 *bufp++ = '\0';
892 done:
893 free(num);
897 * this method changes the meaning of |offset| and |count|:
899 * upon return,
900 * |offset| specifies start of search range
901 * |count| specifies length of search range
903 static void
904 Find_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count )
906 // |count| specifies how many iterations to make from |offset|
908 if (offset < 0)
910 offset = 0;
912 else if (PRUint32(offset) > bigLen)
914 count = 0;
915 return;
918 PRInt32 maxCount = bigLen - offset;
919 if (count < 0 || count > maxCount)
921 count = maxCount;
923 else
925 count += littleLen;
926 if (count > maxCount)
927 count = maxCount;
932 * this method changes the meaning of |offset| and |count|:
934 * upon entry,
935 * |offset| specifies the end point from which to search backwards
936 * |count| specifies the number of iterations from |offset|
938 * upon return,
939 * |offset| specifies start of search range
940 * |count| specifies length of search range
943 * EXAMPLE
945 * + -- littleLen=4 -- +
946 * : :
947 * |____|____|____|____|____|____|____|____|____|____|____|____|
948 * : :
949 * offset=5 bigLen=12
951 * if count = 4, then we expect this function to return offset = 2 and
952 * count = 7.
955 static void
956 RFind_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count )
958 if (littleLen > bigLen)
960 offset = 0;
961 count = 0;
962 return;
965 if (offset < 0)
966 offset = bigLen - littleLen;
967 if (count < 0)
968 count = offset + 1;
970 PRInt32 start = offset - count + 1;
971 if (start < 0)
972 start = 0;
974 count = offset + littleLen - start;
975 offset = start;
978 //-----------------------------------------------------------------------------
980 // define nsString obsolete methods
981 #include "string-template-def-unichar.h"
982 #include "nsTStringObsolete.cpp"
983 #include "string-template-undef.h"
985 // define nsCString obsolete methods
986 #include "string-template-def-char.h"
987 #include "nsTStringObsolete.cpp"
988 #include "string-template-undef.h"
990 //-----------------------------------------------------------------------------
992 // specialized methods:
994 PRInt32
995 nsString::Find( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const
997 // this method changes the meaning of aOffset and aCount:
998 Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
1000 PRInt32 result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE);
1001 if (result != kNotFound)
1002 result += aOffset;
1003 return result;
1006 PRInt32
1007 nsString::Find( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const
1009 return Find(nsDependentString(aString), aOffset, aCount);
1012 PRInt32
1013 nsString::RFind( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const
1015 // this method changes the meaning of aOffset and aCount:
1016 RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount);
1018 PRInt32 result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE);
1019 if (result != kNotFound)
1020 result += aOffset;
1021 return result;
1024 PRInt32
1025 nsString::RFind( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const
1027 return RFind(nsDependentString(aString), aOffset, aCount);
1030 PRInt32
1031 nsString::FindCharInSet( const PRUnichar* aSet, PRInt32 aOffset ) const
1033 if (aOffset < 0)
1034 aOffset = 0;
1035 else if (aOffset >= PRInt32(mLength))
1036 return kNotFound;
1038 PRInt32 result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet);
1039 if (result != kNotFound)
1040 result += aOffset;
1041 return result;
1046 * nsTString::Compare,CompareWithConversion,etc.
1049 PRInt32
1050 nsCString::Compare( const char* aString, PRBool aIgnoreCase, PRInt32 aCount ) const
1052 PRUint32 strLen = char_traits::length(aString);
1054 PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen));
1056 PRInt32 compareCount;
1057 if (aCount < 0 || aCount > maxCount)
1058 compareCount = maxCount;
1059 else
1060 compareCount = aCount;
1062 PRInt32 result =
1063 nsBufferRoutines<char>::compare(mData, aString, compareCount, aIgnoreCase);
1065 if (result == 0 &&
1066 (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount)))
1068 // Since the caller didn't give us a length to test, or strings shorter
1069 // than aCount, and compareCount characters matched, we have to assume
1070 // that the longer string is greater.
1072 if (mLength != strLen)
1073 result = (mLength < strLen) ? -1 : 1;
1075 return result;
1078 PRBool
1079 nsString::EqualsIgnoreCase( const char* aString, PRInt32 aCount ) const
1081 PRUint32 strLen = nsCharTraits<char>::length(aString);
1083 PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen));
1085 PRInt32 compareCount;
1086 if (aCount < 0 || aCount > maxCount)
1087 compareCount = maxCount;
1088 else
1089 compareCount = aCount;
1091 PRInt32 result =
1092 nsBufferRoutines<PRUnichar>::compare(mData, aString, compareCount, PR_TRUE);
1094 if (result == 0 &&
1095 (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount)))
1097 // Since the caller didn't give us a length to test, or strings shorter
1098 // than aCount, and compareCount characters matched, we have to assume
1099 // that the longer string is greater.
1101 if (mLength != strLen)
1102 result = 1; // Arbitrarily using any number != 0
1104 return result == 0;
1108 * nsTString::ToFloat
1111 float
1112 nsCString::ToFloat(PRInt32* aErrorCode) const
1114 float res = 0.0f;
1115 if (mLength > 0)
1117 char *conv_stopped;
1118 const char *str = mData;
1119 // Use PR_strtod, not strtod, since we don't want locale involved.
1120 res = (float)PR_strtod(str, &conv_stopped);
1121 if (conv_stopped == str+mLength)
1122 *aErrorCode = (PRInt32) NS_OK;
1123 else // Not all the string was scanned
1124 *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
1126 else
1128 // The string was too short (0 characters)
1129 *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE;
1131 return res;
1134 float
1135 nsString::ToFloat(PRInt32* aErrorCode) const
1137 return NS_LossyConvertUTF16toASCII(*this).ToFloat(aErrorCode);
1142 * nsTString::AssignWithConversion
1145 void
1146 nsCString::AssignWithConversion( const nsAString& aData )
1148 LossyCopyUTF16toASCII(aData, *this);
1151 void
1152 nsString::AssignWithConversion( const nsACString& aData )
1154 CopyASCIItoUTF16(aData, *this);
1159 * nsTString::AppendWithConversion
1162 void
1163 nsCString::AppendWithConversion( const nsAString& aData )
1165 LossyAppendUTF16toASCII(aData, *this);
1168 void
1169 nsString::AppendWithConversion( const nsACString& aData )
1171 AppendASCIItoUTF16(aData, *this);
1176 * nsTString::AppendInt
1179 void
1180 nsCString::AppendInt( PRInt32 aInteger, PRInt32 aRadix )
1182 char buf[20];
1183 const char* fmt;
1184 switch (aRadix) {
1185 case 8:
1186 fmt = "%o";
1187 break;
1188 case 10:
1189 fmt = "%d";
1190 break;
1191 default:
1192 NS_ASSERTION(aRadix == 16, "Invalid radix!");
1193 fmt = "%x";
1195 PR_snprintf(buf, sizeof(buf), fmt, aInteger);
1196 Append(buf);
1199 void
1200 nsString::AppendInt( PRInt32 aInteger, PRInt32 aRadix )
1202 char buf[20];
1203 const char* fmt;
1204 switch (aRadix) {
1205 case 8:
1206 fmt = "%o";
1207 break;
1208 case 10:
1209 fmt = "%d";
1210 break;
1211 default:
1212 NS_ASSERTION(aRadix == 16, "Invalid radix!");
1213 fmt = "%x";
1215 PR_snprintf(buf, sizeof(buf), fmt, aInteger);
1216 AppendASCIItoUTF16(buf, *this);
1219 void
1220 nsCString::AppendInt( PRInt64 aInteger, PRInt32 aRadix )
1222 char buf[30];
1223 const char* fmt;
1224 switch (aRadix) {
1225 case 8:
1226 fmt = "%llo";
1227 break;
1228 case 10:
1229 fmt = "%lld";
1230 break;
1231 default:
1232 NS_ASSERTION(aRadix == 16, "Invalid radix!");
1233 fmt = "%llx";
1235 PR_snprintf(buf, sizeof(buf), fmt, aInteger);
1236 Append(buf);
1239 void
1240 nsString::AppendInt( PRInt64 aInteger, PRInt32 aRadix )
1242 char buf[30];
1243 const char* fmt;
1244 switch (aRadix) {
1245 case 8:
1246 fmt = "%llo";
1247 break;
1248 case 10:
1249 fmt = "%lld";
1250 break;
1251 default:
1252 NS_ASSERTION(aRadix == 16, "Invalid radix!");
1253 fmt = "%llx";
1255 PR_snprintf(buf, sizeof(buf), fmt, aInteger);
1256 AppendASCIItoUTF16(buf, *this);
1260 * nsTString::AppendFloat
1263 void
1264 nsCString::AppendFloat( float aFloat )
1266 char buf[40];
1267 // Use Modified_cnvtf, which is locale-insensitive, instead of the
1268 // locale-sensitive PR_snprintf or sprintf(3)
1269 Modified_cnvtf(buf, sizeof(buf), 6, aFloat);
1270 Append(buf);
1273 void
1274 nsString::AppendFloat( float aFloat )
1276 char buf[40];
1277 // Use Modified_cnvtf, which is locale-insensitive, instead of the
1278 // locale-sensitive PR_snprintf or sprintf(3)
1279 Modified_cnvtf(buf, sizeof(buf), 6, aFloat);
1280 AppendWithConversion(buf);
1283 void
1284 nsCString::AppendFloat( double aFloat )
1286 char buf[40];
1287 // Use Modified_cnvtf, which is locale-insensitive, instead of the
1288 // locale-sensitive PR_snprintf or sprintf(3)
1289 Modified_cnvtf(buf, sizeof(buf), 15, aFloat);
1290 Append(buf);
1293 void
1294 nsString::AppendFloat( double aFloat )
1296 char buf[40];
1297 // Use Modified_cnvtf, which is locale-insensitive, instead of the
1298 // locale-sensitive PR_snprintf or sprintf(3)
1299 Modified_cnvtf(buf, sizeof(buf), 15, aFloat);
1300 AppendWithConversion(buf);
1303 #endif // !MOZ_STRING_WITH_OBSOLETE_API