Index: src/OFMutableString.m ================================================================== --- src/OFMutableString.m +++ src/OFMutableString.m @@ -243,8 +243,61 @@ @throw [OFInvalidEncodingException newWithClass: isa]; while (--p >= string) *p = tolower((int)*p); + return self; +} + +- replaceOccurrencesOfString: (OFString*)str + withString: (OFString*)repl +{ + const char *str_c = [str cString]; + const char *repl_c = [repl cString]; + size_t str_len = [str length]; + size_t repl_len = [repl length]; + size_t i, last, tmp_len; + char *tmp; + + if (str_len > length) + return self; + + tmp = NULL; + tmp_len = 0; + + for (i = 0, last = 0; i <= length - str_len; i++) { + if (memcmp(string + i, str_c, str_len)) + continue; + + @try { + tmp = [self resizeMem: tmp + toSize: tmp_len + i - last + + repl_len + 1]; + } @catch (OFException *e) { + [self freeMem: tmp]; + @throw e; + } + memcpy(tmp + tmp_len, string + last, i - last); + memcpy(tmp + tmp_len + i - last, repl_c, repl_len); + tmp_len += i - last + repl_len; + i += str_len - 1; + last = i + 1; + } + + @try { + tmp = [self resizeMem: tmp + toSize: tmp_len + length - last + 1]; + } @catch (OFException *e) { + [self freeMem: tmp]; + @throw e; + } + memcpy(tmp + tmp_len, string + last, length - last); + tmp_len += length - last; + tmp[tmp_len] = 0; + + [self freeMem: string]; + string = tmp; + length = tmp_len; + return self; } @end Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -162,10 +162,19 @@ /** * Lower the OFString. */ - lower; +/** + * Replaces all occurrences of a string with another string. + * + * \param str The string to replace + * \param repl The string with which it should be replaced + */ +- replaceOccurrencesOfString: (OFString*)str + withString: (OFString*)repl; + /** * Splits an OFString into an OFArray of OFStrings. * * \param delimiter The delimiter for splitting * \return An autoreleased OFArray with the splitted string Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -325,10 +325,17 @@ @throw [OFNotImplementedException newWithClass: isa andSelector: _cmd]; } - lower +{ + @throw [OFNotImplementedException newWithClass: isa + andSelector: _cmd]; +} + +- replaceOccurrencesOfString: (OFString*)str + withString: (OFString*)repl { @throw [OFNotImplementedException newWithClass: isa andSelector: _cmd]; } Index: tests/OFString/OFString.m ================================================================== --- tests/OFString/OFString.m +++ tests/OFString/OFString.m @@ -23,11 +23,11 @@ #define ZD "%zd" #else #define ZD "%u" #endif -#define NUM_TESTS 25 +#define NUM_TESTS 27 #define SUCCESS \ printf("\r\033[1;%dmTests successful: " ZD "/%d\033[0m", \ (i == NUM_TESTS - 1 ? 32 : 33), i + 1, NUM_TESTS); \ fflush(stdout); #define FAIL \ @@ -111,10 +111,19 @@ CHECK([[@"foo\"ba'_$" urlencode] isEqual: @"foo%22ba%27_%24"]) CHECK([[@"foo%20bar%22%24" urldecode] isEqual: @"foo bar\"$"]) CHECK_EXCEPT([@"foo%bar" urldecode], OFInvalidEncodingException) CHECK_EXCEPT([@"foo%FFbar" urldecode], OFInvalidEncodingException) + + s1 = [@"asd fo asd fofo asd" mutableCopy]; + [s1 replaceOccurrencesOfString: @"fo" + withString: @"foo"]; + CHECK([s1 isEqual: @"asd foo asd foofoo asd"]) + s1 = [@"XX" mutableCopy]; + [s1 replaceOccurrencesOfString: @"X" + withString: @"XX"]; + CHECK([s1 isEqual: @"XXXX"]) puts(""); return 0; }