backport optimisations from trunk

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/branches/stable@26788 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2008-07-15 13:33:37 +00:00
parent 218dc07e77
commit 2cf49edc22
6 changed files with 201 additions and 40 deletions

View file

@ -1,3 +1,12 @@
2008-07-15 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSPrivate.h:
* Source/NSString.m:
* Source/GSString.m:
* Source/GSeq.h:
* Testing/string.m:
Backport optimisations and improved argument checking from trunk.
2008-07-01 Richard Frith-Macdonald <rfm@gnu.org> 2008-07-01 Richard Frith-Macdonald <rfm@gnu.org>
* Source/Additions/Unicode.m: Add support for byte order specific * Source/Additions/Unicode.m: Add support for byte order specific

View file

@ -418,6 +418,12 @@ void GSPrivateNotifyIdle(void) GS_ATTRIB_PRIVATE;
*/ */
BOOL GSPrivateNotifyMore(void) GS_ATTRIB_PRIVATE; BOOL GSPrivateNotifyMore(void) GS_ATTRIB_PRIVATE;
/* Function to return the function for searching in a string for a range.
*/
typedef NSRange (*GSRSFunc)(id, id, unsigned, NSRange);
GSRSFunc
GSPrivateRangeOfString(NSString *receiver, NSString *target) GS_ATTRIB_PRIVATE;
/* Function to return the current stack return addresses. /* Function to return the current stack return addresses.
*/ */
NSMutableArray * NSMutableArray *

View file

@ -216,6 +216,16 @@ typedef struct {
#define GSEQ_S GSEQ_CS #define GSEQ_S GSEQ_CS
#include "GSeq.h" #include "GSeq.h"
/*
* Include sequence handling code with instructions to generate search
* and compare functions for NSString objects.
*/
#define GSEQ_STRCOMP strCompNsNs
#define GSEQ_STRRANGE strRangeNsNs
#define GSEQ_O GSEQ_NS
#define GSEQ_S GSEQ_NS
#include "GSeq.h"
static Class NSDataClass = 0; static Class NSDataClass = 0;
static Class NSStringClass = 0; static Class NSStringClass = 0;
static Class GSStringClass = 0; static Class GSStringClass = 0;
@ -254,6 +264,10 @@ setup(void)
{ {
beenHere = YES; beenHere = YES;
caiSel = @selector(characterAtIndex:);
gcrSel = @selector(getCharacters:range:);
ranSel = @selector(rangeOfComposedCharacterSequenceAtIndex:);
/* /*
* Cache the default string encoding, and set the internal encoding * Cache the default string encoding, and set the internal encoding
* used by 8-bit character strings to match if possible. * used by 8-bit character strings to match if possible.
@ -1141,11 +1155,6 @@ compare_c(GSStr self, NSString *aString, unsigned mask, NSRange aRange)
{ {
Class c; Class c;
if (aString == nil)
[NSException raise: NSInvalidArgumentException format: @"compare with nil"];
if (GSObjCIsInstance(aString) == NO)
return strCompCsNs((id)self, aString, mask, aRange);
c = GSObjCClass(aString); c = GSObjCClass(aString);
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|| (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1)) || (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1))
@ -1163,11 +1172,6 @@ compare_u(GSStr self, NSString *aString, unsigned mask, NSRange aRange)
{ {
Class c; Class c;
if (aString == nil)
[NSException raise: NSInvalidArgumentException format: @"compare with nil"];
if (GSObjCIsInstance(aString) == NO)
return strCompUsNs((id)self, aString, mask, aRange);
c = GSObjCClass(aString); c = GSObjCClass(aString);
if (GSObjCIsKindOf(c, GSUnicodeStringClass) if (GSObjCIsKindOf(c, GSUnicodeStringClass)
|| (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1)) || (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1))
@ -2409,7 +2413,7 @@ rangeOfCharacter_c(GSStr self, NSCharacterSet *aSet, unsigned mask,
{ {
unichar u = self->_contents.c[i]; unichar u = self->_contents.c[i];
if (u > 127) if (u > 127 && internalEncoding != NSISOLatin1StringEncoding)
{ {
unsigned char c = (unsigned char)u; unsigned char c = (unsigned char)u;
unsigned int s = 1; unsigned int s = 1;
@ -2417,6 +2421,9 @@ rangeOfCharacter_c(GSStr self, NSCharacterSet *aSet, unsigned mask,
GSToUnicode(&d, &s, &c, 1, internalEncoding, 0, 0); GSToUnicode(&d, &s, &c, 1, internalEncoding, 0, 0);
} }
/* FIXME ... what about UTF-16 sequences of more than one 16bit value
* corresponding to a single UCS-32 codepoint?
*/
if ((*mImp)(aSet, cMemberSel, u)) if ((*mImp)(aSet, cMemberSel, u))
{ {
range = NSMakeRange(i, 1); range = NSMakeRange(i, 1);
@ -2456,6 +2463,9 @@ rangeOfCharacter_u(GSStr self, NSCharacterSet *aSet, unsigned mask,
mImp = (BOOL(*)(id,SEL,unichar)) mImp = (BOOL(*)(id,SEL,unichar))
[aSet methodForSelector: cMemberSel]; [aSet methodForSelector: cMemberSel];
/* FIXME ... what about UTF-16 sequences of more than one 16bit value
* corresponding to a single UCS-32 codepoint?
*/
for (i = start; i != stop; i += step) for (i = start; i != stop; i += step)
{ {
unichar letter = self->_contents.u[i]; unichar letter = self->_contents.u[i];
@ -2470,16 +2480,52 @@ rangeOfCharacter_u(GSStr self, NSCharacterSet *aSet, unsigned mask,
return range; return range;
} }
GSRSFunc
GSPrivateRangeOfString(NSString *receiver, NSString *target)
{
Class c;
c = GSObjCClass(receiver);
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|| (c == GSMutableStringClass && ((GSStr)receiver)->_flags.wide == 1))
{
c = GSObjCClass(target);
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|| (c == GSMutableStringClass && ((GSStr)target)->_flags.wide == 1))
return (GSRSFunc)strRangeUsUs;
else if (GSObjCIsKindOf(c, GSCStringClass) == YES
|| c == NSConstantStringClass
|| (c == GSMutableStringClass && ((GSStr)target)->_flags.wide == 0))
return (GSRSFunc)strRangeUsCs;
else
return (GSRSFunc)strRangeUsNs;
}
else if (GSObjCIsKindOf(c, GSCStringClass) == YES
|| c == NSConstantStringClass
|| (c == GSMutableStringClass && ((GSStr)target)->_flags.wide == 0))
{
c = GSObjCClass(target);
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|| (c == GSMutableStringClass && ((GSStr)target)->_flags.wide == 1))
return (GSRSFunc)strRangeCsUs;
else if (GSObjCIsKindOf(c, GSCStringClass) == YES
|| c == NSConstantStringClass
|| (c == GSMutableStringClass && ((GSStr)target)->_flags.wide == 0))
return (GSRSFunc)strRangeCsCs;
else
return (GSRSFunc)strRangeCsNs;
}
else
{
return (GSRSFunc)strRangeNsNs;
}
}
static inline NSRange static inline NSRange
rangeOfString_c(GSStr self, NSString *aString, unsigned mask, NSRange aRange) rangeOfString_c(GSStr self, NSString *aString, unsigned mask, NSRange aRange)
{ {
Class c; Class c;
if (aString == nil)
[NSException raise: NSInvalidArgumentException format: @"range of nil"];
if (GSObjCIsInstance(aString) == NO)
return strRangeCsNs((id)self, aString, mask, aRange);
c = GSObjCClass(aString); c = GSObjCClass(aString);
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|| (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1)) || (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1))
@ -2497,11 +2543,6 @@ rangeOfString_u(GSStr self, NSString *aString, unsigned mask, NSRange aRange)
{ {
Class c; Class c;
if (aString == nil)
[NSException raise: NSInvalidArgumentException format: @"range of nil"];
if (GSObjCIsInstance(aString) == NO)
return strRangeUsNs((id)self, aString, mask, aRange);
c = GSObjCClass(aString); c = GSObjCClass(aString);
if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES if (GSObjCIsKindOf(c, GSUnicodeStringClass) == YES
|| (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1)) || (c == GSMutableStringClass && ((GSStr)aString)->_flags.wide == 1))
@ -2779,6 +2820,15 @@ transmute(GSStr self, NSString *aString)
options: (unsigned int)mask options: (unsigned int)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, _count);
if (aString == nil)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] nil string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (GSObjCIsInstance(aString) == NO)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] not a string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
return compare_c((GSStr)self, aString, mask, aRange); return compare_c((GSStr)self, aString, mask, aRange);
} }
@ -2955,6 +3005,15 @@ transmute(GSStr self, NSString *aString)
options: (unsigned)mask options: (unsigned)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, _count);
if (aString == nil)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] nil string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (GSObjCIsInstance(aString) == NO)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] not a string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
return rangeOfString_c((GSStr)self, aString, mask, aRange); return rangeOfString_c((GSStr)self, aString, mask, aRange);
} }
@ -3091,6 +3150,15 @@ agree, create a new GSCInlineString otherwise.
options: (unsigned int)mask options: (unsigned int)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, _count);
if (aString == nil)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] nil string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (GSObjCIsInstance(aString) == NO)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] not a string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
return compare_u((GSStr)self, aString, mask, aRange); return compare_u((GSStr)self, aString, mask, aRange);
} }
@ -3268,6 +3336,15 @@ agree, create a new GSCInlineString otherwise.
options: (unsigned)mask options: (unsigned)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, _count);
if (aString == nil)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] nil string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (GSObjCIsInstance(aString) == NO)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] not a string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
return rangeOfString_u((GSStr)self, aString, mask, aRange); return rangeOfString_u((GSStr)self, aString, mask, aRange);
} }
@ -3474,6 +3551,15 @@ agree, create a new GSUnicodeInlineString otherwise.
options: (unsigned int)mask options: (unsigned int)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, _count);
if (aString == nil)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] nil string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (GSObjCIsInstance(aString) == NO)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] not a string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (_flags.wide == 1) if (_flags.wide == 1)
return compare_u((GSStr)self, aString, mask, aRange); return compare_u((GSStr)self, aString, mask, aRange);
else else
@ -4066,6 +4152,15 @@ NSAssert(_flags.free == 1 && _zone != 0, NSInternalInconsistencyException);
options: (unsigned)mask options: (unsigned)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, _count);
if (aString == nil)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] nil string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (GSObjCIsInstance(aString) == NO)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] not a string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (_flags.wide == 1) if (_flags.wide == 1)
return rangeOfString_u((GSStr)self, aString, mask, aRange); return rangeOfString_u((GSStr)self, aString, mask, aRange);
else else
@ -4529,6 +4624,7 @@ NSAssert(_flags.free == 1 && _zone != 0, NSInternalInconsistencyException);
options: (unsigned)mask options: (unsigned)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, ((GSStr)_parent)->_count);
return [_parent rangeOfCharacterFromSet: aSet options: mask range: aRange]; return [_parent rangeOfCharacterFromSet: aSet options: mask range: aRange];
} }
@ -4536,6 +4632,15 @@ NSAssert(_flags.free == 1 && _zone != 0, NSInternalInconsistencyException);
options: (unsigned)mask options: (unsigned)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, ((GSStr)_parent)->_count);
if (aString == nil)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] nil string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (GSObjCIsInstance(aString) == NO)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] not a string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
return [_parent rangeOfString: aString options: mask range: aRange]; return [_parent rangeOfString: aString options: mask range: aRange];
} }
@ -4574,6 +4679,15 @@ NSAssert(_flags.free == 1 && _zone != 0, NSInternalInconsistencyException);
options: (unsigned int)mask options: (unsigned int)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, ((GSStr)_parent)->_count);
if (aString == nil)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] nil string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (GSObjCIsInstance(aString) == NO)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] not a string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (((GSStr)_parent)->_flags.wide == 1) if (((GSStr)_parent)->_flags.wide == 1)
return compare_u((GSStr)_parent, aString, mask, aRange); return compare_u((GSStr)_parent, aString, mask, aRange);
else else
@ -4727,6 +4841,15 @@ NSAssert(_flags.free == 1 && _zone != 0, NSInternalInconsistencyException);
options: (unsigned)mask options: (unsigned)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, ((GSStr)_parent)->_count);
if (aString == nil)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] nil string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (GSObjCIsInstance(aString) == NO)
[NSException raise: NSInvalidArgumentException
format: @"[%@ -%@] not a string argument",
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
if (((GSStr)_parent)->_flags.wide == 1) if (((GSStr)_parent)->_flags.wide == 1)
return rangeOfString_u((GSStr)_parent, aString, mask, aRange); return rangeOfString_u((GSStr)_parent, aString, mask, aRange);
else else
@ -4858,7 +4981,7 @@ NSAssert(_flags.free == 1 && _zone != 0, NSInternalInconsistencyException);
{ {
unichar u = *p++; unichar u = *p++;
if (u > 127) if (u > 127 && internalEncoding != NSISOLatin1StringEncoding)
{ {
unsigned char c = (unsigned char)u; unsigned char c = (unsigned char)u;
unsigned int s = 1; unsigned int s = 1;

View file

@ -20,7 +20,8 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02111 USA.
*/ */
/* /*
@ -40,7 +41,7 @@
/* /*
* Some standard selectors for frequently used methods. Set in NSString * Some standard selectors for frequently used methods. Set in NSString
* +initialize. * +initialize or the GSString.m setup() function.
*/ */
static SEL caiSel = NULL; static SEL caiSel = NULL;
static SEL gcrSel = NULL; static SEL gcrSel = NULL;
@ -380,10 +381,13 @@ GSEQ_STRCOMP(NSString *ss, NSString *os, unsigned mask, NSRange aRange)
unsigned oLength; /* Length of other. */ unsigned oLength; /* Length of other. */
unsigned sLength = GSEQ_SLEN; unsigned sLength = GSEQ_SLEN;
#if 0
/* Range should be checked in calling code */
if (aRange.location > sLength) if (aRange.location > sLength)
[NSException raise: NSRangeException format: @"Invalid location."]; [NSException raise: NSRangeException format: @"Invalid location."];
if (aRange.length > (sLength - aRange.location)) if (aRange.length > (sLength - aRange.location))
[NSException raise: NSRangeException format: @"Invalid location+length."]; [NSException raise: NSRangeException format: @"Invalid location+length."];
#endif
oLength = GSEQ_OLEN; oLength = GSEQ_OLEN;
if (aRange.length == 0) if (aRange.length == 0)
@ -603,11 +607,14 @@ GSEQ_STRRANGE(NSString *ss, NSString *os, unsigned mask, NSRange aRange)
/* Check that the search range is reasonable */ /* Check that the search range is reasonable */
myLength = GSEQ_SLEN; myLength = GSEQ_SLEN;
#if 0
/* Range should be checked in calling code */
if (aRange.location > myLength) if (aRange.location > myLength)
[NSException raise: NSRangeException format: @"Invalid location."]; [NSException raise: NSRangeException format: @"Invalid location."];
if (aRange.length > (myLength - aRange.location)) if (aRange.length > (myLength - aRange.location))
[NSException raise: NSRangeException format: @"Invalid location+length."]; [NSException raise: NSRangeException format: @"Invalid location+length."];
#endif
/* Ensure the string can be found */ /* Ensure the string can be found */
strLength = GSEQ_OLEN; strLength = GSEQ_OLEN;

View file

@ -1450,11 +1450,11 @@ handle_printf_atsign (FILE *stream,
{ {
unsigned char *src = (unsigned char*)[data bytes]; unsigned char *src = (unsigned char*)[data bytes];
unsigned int slen = [data length]; unsigned int slen = [data length];
NSMutableData *d = [[NSMutableData alloc] initWithLength: slen * 3]; unsigned char *dst;
unsigned char *dst = (unsigned char*)[d mutableBytes];
unsigned int spos = 0; unsigned int spos = 0;
unsigned int dpos = 0; unsigned int dpos = 0;
dst = (unsigned char*)NSZoneMalloc(NSDefaultMallocZone(), slen * 3);
while (spos < slen) while (spos < slen)
{ {
unsigned char c = src[spos++]; unsigned char c = src[spos++];
@ -1476,9 +1476,10 @@ handle_printf_atsign (FILE *stream,
dst[dpos++] = c; dst[dpos++] = c;
} }
} }
[d setLength: dpos]; s = [[NSString alloc] initWithBytes: dst
s = [[NSString alloc] initWithData: d encoding: NSASCIIStringEncoding]; length: dpos
RELEASE(d); encoding: NSASCIIStringEncoding];
NSZoneFree(NSDefaultMallocZone(), dst);
AUTORELEASE(s); AUTORELEASE(s);
} }
return s; return s;
@ -1809,6 +1810,7 @@ handle_printf_atsign (FILE *stream,
options: (unsigned int)mask options: (unsigned int)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, [self length]);
if (aString == nil) if (aString == nil)
[NSException raise: NSInvalidArgumentException format: @"range of nil"]; [NSException raise: NSInvalidArgumentException format: @"range of nil"];
return strRangeNsNs(self, aString, mask, aRange); return strRangeNsNs(self, aString, mask, aRange);
@ -1917,6 +1919,7 @@ handle_printf_atsign (FILE *stream,
options: (unsigned int)mask options: (unsigned int)mask
range: (NSRange)aRange range: (NSRange)aRange
{ {
GS_RANGE_CHECK(aRange, [self length]);
if (aString == nil) if (aString == nil)
[NSException raise: NSInvalidArgumentException format: @"compare with nil"]; [NSException raise: NSInvalidArgumentException format: @"compare with nil"];
return strCompNsNs(self, aString, mask, aRange); return strCompNsNs(self, aString, mask, aRange);
@ -4967,28 +4970,38 @@ static NSFileManager *fm = nil;
{ {
NSRange range; NSRange range;
unsigned int count = 0; unsigned int count = 0;
GSRSFunc func;
if (replace == nil) if ([replace isKindOfClass: NSStringClass] == NO)
{ {
[NSException raise: NSInvalidArgumentException [NSException raise: NSInvalidArgumentException
format: @"%@ nil search string", NSStringFromSelector(_cmd)]; format: @"%@ bad search string", NSStringFromSelector(_cmd)];
} }
if (by == nil) if ([by isKindOfClass: NSStringClass] == NO)
{ {
[NSException raise: NSInvalidArgumentException [NSException raise: NSInvalidArgumentException
format: @"%@ nil replace string", NSStringFromSelector(_cmd)]; format: @"%@ bad replace string", NSStringFromSelector(_cmd)];
} }
range = [self rangeOfString: replace options: opts range: searchRange]; if (NSMaxRange(searchRange) > [self length])
{
[NSException raise: NSInvalidArgumentException
format: @"%@ bad search range", NSStringFromSelector(_cmd)];
}
func = GSPrivateRangeOfString(self, replace);
range = (*func)(self, replace, opts, searchRange);
if (range.length > 0) if (range.length > 0)
{ {
unsigned byLen = [by length]; unsigned byLen = [by length];
SEL sel;
void (*imp)(id, SEL, NSRange, NSString*);
sel = @selector(replaceCharactersInRange:withString:);
imp = (void(*)(id, SEL, NSRange, NSString*))[self methodForSelector: sel];
do do
{ {
count++; count++;
[self replaceCharactersInRange: range (*imp)(self, sel, range, by);
withString: by];
if ((opts & NSBackwardsSearch) == NSBackwardsSearch) if ((opts & NSBackwardsSearch) == NSBackwardsSearch)
{ {
searchRange.length = range.location - searchRange.location; searchRange.length = range.location - searchRange.location;
@ -5002,9 +5015,7 @@ static NSFileManager *fm = nil;
searchRange.length = newEnd - searchRange.location; searchRange.length = newEnd - searchRange.location;
} }
range = [self rangeOfString: replace range = (*func)(self, replace, opts, searchRange);
options: opts
range: searchRange];
} }
while (range.length > 0); while (range.length > 0);
} }

View file

@ -101,6 +101,11 @@ int main()
[s2 replaceCharactersInRange:((NSRange){10,4}) [s2 replaceCharactersInRange:((NSRange){10,4})
withString:@"changed"]; withString:@"changed"];
print_string(s2); print_string(s2);
[s2 replaceOccurrencesOfString: @"changed"
withString: @"changed again"
options: NSLiteralSearch
range: NSMakeRange(0, [s2 length])];
print_string(s2);
#if 0 #if 0
/* Test the use of the `%@' format directive. */ /* Test the use of the `%@' format directive. */