Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -124,10 +124,19 @@ * \return An integer which is the result of the comparison, see for example * strcmp */ - (int)compare: (id)obj; +/** + * \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 + */ +- (OFString*)substringFromIndex: (size_t)start + toIndex: (size_t)end; + /** * 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 @@ -308,10 +308,43 @@ OF_HASH_ADD(hash, string[i]); OF_HASH_FINALIZE(hash); return hash; } + +- (OFString*)substringFromIndex: (size_t)start + toIndex: (size_t)end +{ + char *tmp; + size_t len; + OFString *ret; + + if (start > end) + @throw [OFInvalidArgumentException newWithClass: isa + andSelector: _cmd]; + + if (end > length) + @throw [OFOutOfRangeException newWithClass: isa]; + + len = end - start; + + if ((tmp = malloc(len + 1)) == NULL) + @throw [OFOutOfMemoryException newWithClass: isa + andSize: len + 1]; + + if (len) + memcpy(tmp, string + start, len); + tmp[len] = 0; + + @try { + ret = [OFString stringWithCString: tmp]; + } @finally { + free(tmp); + } + + return ret; +} - (OFArray*)splitWithDelimiter: (OFString*)delimiter { OFAutoreleasePool *pool; OFArray *array = nil; 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 34 +#define NUM_TESTS 39 #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,22 @@ CHECK(!strcmp([s1 cString], "test: 123")) [s1 appendWithFormat: @"%02X", 15]; CHECK(!strcmp([s1 cString], "test: 1230F")) + /* Substring tests */ + CHECK([[@"foo" substringFromIndex: 1 + toIndex: 2] isEqual: @"o"]); + CHECK([[@"foo" substringFromIndex: 3 + toIndex: 3] isEqual: @""]); + CHECK_EXCEPT([@"foo" substringFromIndex: 2 + toIndex: 4], OFOutOfRangeException) + CHECK_EXCEPT([@"foo" substringFromIndex: 4 + toIndex: 4], OFOutOfRangeException) + CHECK_EXCEPT([@"foo" substringFromIndex: 2 + toIndex: 0], OFInvalidArgumentException) + /* Split tests */ a = [@"fooXXbarXXXXbazXXXX" splitWithDelimiter: @"XX"]; CHECK([[a objectAtIndex: j++] isEqual: @"foo"]) CHECK([[a objectAtIndex: j++] isEqual: @"bar"]) CHECK([[a objectAtIndex: j++] isEqual: @""])