Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -124,10 +124,24 @@ * \return An integer which is the result of the comparison, see for example * strcmp */ - (int)compare: (id)obj; +/** + * \param str The string to search + * \return The index of the first occurrence of the string or SIZE_MAX if it + * wasn't found + */ +- (size_t)indexOfFirstOccurrenceOfString: (OFString*)str; + +/** + * \param str The string to search + * \return The index of the last occurrence of the string or SIZE_MAX if it + * wasn't found + */ +- (size_t)indexOfLastOccurrenceOfString: (OFString*)str; + /** * \param start The index where the substring starts * \param end The index where the substring ends. * This points BEHIND the last character! * \return The substring as a new autoreleased OFString Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -308,10 +308,51 @@ OF_HASH_ADD(hash, string[i]); OF_HASH_FINALIZE(hash); return hash; } + +- (size_t)indexOfFirstOccurrenceOfString: (OFString*)str +{ + const char *str_c = [str cString]; + size_t str_len = [str length]; + size_t i; + + if (str_len == 0) + return 0; + + if (str_len > length) + return SIZE_MAX; + + for (i = 0; i <= length - str_len; i++) + if (!memcmp(string + i, str_c, str_len)) + return i; + + return SIZE_MAX; +} + +- (size_t)indexOfLastOccurrenceOfString: (OFString*)str +{ + const char *str_c = [str cString]; + size_t str_len = [str length]; + size_t i; + + if (str_len == 0) + return length; + + if (str_len > length) + return SIZE_MAX; + + for (i = length - str_len;; i--) { + if (!memcmp(string + i, str_c, str_len)) + return i; + + /* Did not match and we're at the last char */ + if (i == 0) + return SIZE_MAX; + } +} - (OFString*)substringFromIndex: (size_t)start toIndex: (size_t)end { char *tmp; 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 39 +#define NUM_TESTS 47 #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 \ @@ -99,10 +99,20 @@ CHECK(!strcmp([s1 cString], "test: 123")) [s1 appendWithFormat: @"%02X", 15]; CHECK(!strcmp([s1 cString], "test: 1230F")) + /* Find index tests */ + CHECK([@"foo" indexOfFirstOccurrenceOfString: @"oo"] == 1) + CHECK([@"foo" indexOfLastOccurrenceOfString: @"oo"] == 1) + CHECK([@"foo" indexOfFirstOccurrenceOfString: @"o"] == 1) + CHECK([@"foo" indexOfLastOccurrenceOfString: @"o"] == 2) + CHECK([@"foo" indexOfFirstOccurrenceOfString: @"f"] == 0) + CHECK([@"foo" indexOfLastOccurrenceOfString: @"f"] == 0) + CHECK([@"foo" indexOfFirstOccurrenceOfString: @"x"] == SIZE_MAX) + CHECK([@"foo" indexOfLastOccurrenceOfString: @"x"] == SIZE_MAX) + /* Substring tests */ CHECK([[@"foo" substringFromIndex: 1 toIndex: 2] isEqual: @"o"]); CHECK([[@"foo" substringFromIndex: 3 toIndex: 3] isEqual: @""]);