ObjFW  Check-in [e7e8efd297]

Overview
Comment:More separation for OFString and OFMutableString.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e7e8efd2975a632015c1f5a76c61a9c1e4ed9a5dc55a051eb75ce0e2322965fa
User & Date: js on 2009-05-18 18:09:08
Other Links: manifest | tags
Context
2009-05-18
18:15
Introduce OFMutableCopying protocol. check-in: 79e1893b40 user: js tags: trunk
18:09
More separation for OFString and OFMutableString. check-in: e7e8efd297 user: js tags: trunk
17:50
Split OFArray into OFArray and OFMutableArray. check-in: 163409967e user: js tags: trunk
Changes

Modified src/OFMutableString.h from [0dde8a8b94] to [50d5f8f8b9].

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
14
15
16
17
18
19
20































21







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-


#import "OFString.h"

/**
 * A class for storing and modifying strings.
 */
@interface OFMutableString: OFString
{
	BOOL   is_utf8;
}

/**
 * Initializes an already allocated OFMutableString from a C string.
 *
 * \param str A C string to initialize the OFMutableString with
 * \return An initialized OFMutableString
 */
- initWithCString: (const char*)str;

/**
 * Initializes an already allocated OFMutableString from a format C string.
 * See printf for the format syntax.
 *
 * \param fmt A string used as format to initialize the OFMutableString
 * \return An initialized OFMutableString
 */
- initWithFormat: (OFString*)fmt, ...;

/**
 * Initializes an already allocated OFMutableString from a format C string.
 * See printf for the format syntax.
 *
 * \param fmt A string used as format to initialize the OFMutableString
 * \param args The arguments used in the format string
 * \return An initialized OFMutableString
 */
- initWithFormat: (OFString*)fmt
    andArguments: (va_list)args;
@end

Modified src/OFMutableString.m from [9dc4884694] to [61830ce984].

8
9
10
11
12
13
14
15
16
17



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
8
9
10
11
12
13
14



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34






































































35

36




























































































37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
52







-
-
-
+
+
+

















-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-

-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-








-
+







 * Q Public License 1.0, which can be found in the file LICENSE included in
 * the packaging of this file.
 */

#import "config.h"

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#else
#define madvise(addr, len, advise)
#endif

#import "OFMutableString.h"
#import "OFExceptions.h"
#import "OFMacros.h"

#ifndef HAVE_ASPRINTF
#import "asprintf.h"
#endif

static OF_INLINE int
check_utf8(const char *str, size_t len)
{
	size_t i;
	BOOL utf8;

	utf8 = NO;

	madvise((void*)str, len, MADV_SEQUENTIAL);

	for (i = 0; i < len; i++) {
		/* No sign of UTF-8 here */
		if (OF_LIKELY(!(str[i] & 0x80)))
			continue;

		utf8 = YES;

		/* We're missing a start byte here */
		if (OF_UNLIKELY(!(str[i] & 0x40))) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		/* We have at minimum a 2 byte character -> check next byte */
		if (OF_UNLIKELY(len < i + 1 || (str[i + 1] & 0xC0) != 0x80)) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		/* Check if we have at minimum a 3 byte character */
		if (OF_LIKELY(!(str[i] & 0x20))) {
			i++;
			continue;
		}

		/* We have at minimum a 3 byte char -> check second next byte */
		if (OF_UNLIKELY(len < i + 2 || (str[i + 2] & 0xC0) != 0x80)) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		/* Check if we have a 4 byte character */
		if (OF_LIKELY(!(str[i] & 0x10))) {
			i += 2;
			continue;
		}

		/* We have a 4 byte character -> check third next byte */
		if (OF_UNLIKELY(len < i + 3 || (str[i + 3] & 0xC0) != 0x80)) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		/*
		 * Just in case, check if there's a 5th character, which is
		 * forbidden by UTF-8
		 */
		if (OF_UNLIKELY(str[i] & 0x08)) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		i += 3;
	}

	madvise((void*)str, len, MADV_NORMAL);

	return (utf8 ? 1 : 0);
}

@implementation OFMutableString
- initWithCString: (const char*)str
- setToCString: (const char*)str
{
	Class c;

	self = [super init];

	if (str != NULL) {
		length = strlen(str);

		switch (check_utf8(str, length)) {
			case 1:
				is_utf8 = YES;
				break;
			case -1:
				c = isa;
				[super dealloc];
				@throw [OFInvalidEncodingException
					newWithClass: c];
		}

		@try {
			string = [self allocWithSize: length + 1];
		} @catch (OFException *e) {
			/*
			 * We can't use [super dealloc] on OS X here.
			 * Compiler bug? Anyway, [self dealloc] will do here as
			 * we don't reimplement dealloc.
			 */
			[self dealloc];
			@throw e;
		}
		memcpy(string, str, length + 1);
	}

	return self;
}

- initWithFormat: (OFString*)fmt, ...
{
	id ret;
	va_list args;

	va_start(args, fmt);
	ret = [self initWithFormat: fmt
		      andArguments: args];
	va_end(args);

	return ret;
}

- initWithFormat: (OFString*)fmt
    andArguments: (va_list)args
{
	int t;
	Class c;

	self = [super init];

	if (fmt == NULL) {
		c = isa;
		[super dealloc];
		@throw [OFInvalidFormatException newWithClass: c];
	}

	if ((t = vasprintf(&string, [fmt cString], args)) == -1) {
		c = isa;
		[super dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}
	length = t;

	switch (check_utf8(string, length)) {
		case 1:
			is_utf8 = YES;
			break;
		case -1:
			free(string);
			c = isa;
			[super dealloc];
			@throw [OFInvalidEncodingException newWithClass: c];
	}

	@try {
		[self addToMemoryPool: string];
	} @catch (OFException *e) {
		free(string);
		@throw e;
	}

	return self;
}

- setTo: (const char*)str
{
	size_t len;

	if (string != NULL)
		[self freeMem: string];

	len = strlen(str);

	switch (check_utf8(str, len)) {
	switch (of_string_check_utf8(str, len)) {
	case 1:
		is_utf8 = YES;
		break;
	case -1:
		string = NULL;
		length = 0;
		is_utf8 = NO;
230
231
232
233
234
235
236
237

238
239
240
241
242
243
244
68
69
70
71
72
73
74

75
76
77
78
79
80
81
82







-
+








- appendCString: (const char*)str
{
	size_t strlength;

	strlength = strlen(str);

	switch (check_utf8(str, strlength)) {
	switch (of_string_check_utf8(str, strlength)) {
	case 1:
		is_utf8 = YES;
		break;
	case -1:
		@throw [OFInvalidEncodingException newWithClass: isa];
	}

Modified src/OFString.h from [71d4835865] to [b7ca2d5c06].

11
12
13
14
15
16
17


18
19
20
21
22
23
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48

49
50
51
52
53
54
55
56
57

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73




























74
75
76
77
78
79
80
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58
59

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111







+
+














+








-
+







-
+








-
+
















+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








#include <stdio.h>
#include <stdarg.h>

#import "OFObject.h"
#import "OFArray.h"

extern int of_string_check_utf8(const char *str, size_t len);

/**
 * A class for managing strings.
 */
@interface OFString: OFObject <OFCopying>
{
	char	     *string;
#ifdef __objc_INCLUDE_GNU
	unsigned int length;
#else
	int	     length;
#if __LP64__
	int	     _unused;
#endif
#endif
	BOOL	     is_utf8;
}

/**
 * \return A new autoreleased OFMutableString
 */
+ string;

/**
 * Creates a new OFMutableString from a C string.
 * Creates a new OFString from a C string.
 *
 * \param str A C string to initialize the OFMutableString with
 * \return A new autoreleased OFMutableString
 */
+ stringWithCString: (const char*)str;

/**
 * Creates a new OFMutableString from a format C string.
 * Creates a new OFString from a format C string.
 * See printf for the format syntax.
 *
 * \param fmt A string used as format to initialize the OFMutableString
 * \return A new autoreleased OFMutableString
 */
+ stringWithFormat: (OFString*)fmt, ...;

/**
 * Creates a new OFMutableString from a format C string.
 * Creates a new OFString from a format C string.
 * See printf for the format syntax.
 *
 * \param fmt A string used as format to initialize the OFMutableString
 * \param args The arguments used in the format string
 * \return A new autoreleased OFMutableString
 */
+ stringWithFormat: (OFString*)fmt
      andArguments: (va_list)args;

/**
 * Initializes an already allocated OFString.
 *
 * \return An initialized OFString
 */
- init;

/**
 * Initializes an already allocated OFMutableString from a C string.
 *
 * \param str A C string to initialize the OFMutableString with
 * \return An initialized OFMutableString
 */
- initWithCString: (const char*)str;

/**
 * Initializes an already allocated OFMutableString from a format C string.
 * See printf for the format syntax.
 *
 * \param fmt A string used as format to initialize the OFMutableString
 * \return An initialized OFMutableString
 */
- initWithFormat: (OFString*)fmt, ...;

/**
 * Initializes an already allocated OFMutableString from a format C string.
 * See printf for the format syntax.
 *
 * \param fmt A string used as format to initialize the OFMutableString
 * \param args The arguments used in the format string
 * \return An initialized OFMutableString
 */
- initWithFormat: (OFString*)fmt
    andArguments: (va_list)args;

/**
 * \return The OFString as a C string
 */
- (const char*)cString;

/**
 * \return The length of the OFString
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
122
123
124
125
126
127
128

129
130
131
132
133
134
135
136







-
+







- (int)compare: (id)obj;

/**
 * Sets the OFString to the specified OFString.
 *
 * \param str An OFString to set the OFString to.
 */
- setTo: (const char*)str;
- setToCString: (const char*)str;

/**
 * Appends another OFString to the OFString.
 *
 * \param str An OFString to append
 */
- append: (OFString*)str;

Modified src/OFString.m from [1c15b5afa3] to [b1b2906cfa].

1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16






17
18
19
20
21
22
23




24
25
26
27
28
29




































































30
31
32
33

34
35
36
37
38

39
40
41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56
57

58
59
60
61
62
63
64
65




























































































66
67
68
69
70
71
72
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

112
113
114
115
116

117
118
119
120
121
122
123
124
125

126
127
128
129
130
131
132
133
134
135

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243













+



+
+
+
+
+
+







+
+
+
+






+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



-
+




-
+








-
+









-
+








+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







/*
 * Copyright (c) 2008 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of libobjfw. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE included in
 * the packaging of this file.
 */

#import "config.h"

#define _GNU_SOURCE
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#else
#define madvise(addr, len, advise)
#endif

#import "OFString.h"
#import "OFAutoreleasePool.h"
#import "OFURLEncoding.h"
#import "OFExceptions.h"
#import "OFMacros.h"

#ifndef HAVE_ASPRINTF
#import "asprintf.h"
#endif

/* Reference for static linking */
void _reference_to_OFURLEncoding_in_OFString()
{
	_OFURLEncoding_reference = 1;
};

int
of_string_check_utf8(const char *str, size_t len)
{
	size_t i;
	int utf8 = 0;

	madvise((void*)str, len, MADV_SEQUENTIAL);

	for (i = 0; i < len; i++) {
		/* No sign of UTF-8 here */
		if (OF_LIKELY(!(str[i] & 0x80)))
			continue;

		utf8 = 1;

		/* We're missing a start byte here */
		if (OF_UNLIKELY(!(str[i] & 0x40))) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		/* We have at minimum a 2 byte character -> check next byte */
		if (OF_UNLIKELY(len < i + 1 || (str[i + 1] & 0xC0) != 0x80)) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		/* Check if we have at minimum a 3 byte character */
		if (OF_LIKELY(!(str[i] & 0x20))) {
			i++;
			continue;
		}

		/* We have at minimum a 3 byte char -> check second next byte */
		if (OF_UNLIKELY(len < i + 2 || (str[i + 2] & 0xC0) != 0x80)) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		/* Check if we have a 4 byte character */
		if (OF_LIKELY(!(str[i] & 0x10))) {
			i += 2;
			continue;
		}

		/* We have a 4 byte character -> check third next byte */
		if (OF_UNLIKELY(len < i + 3 || (str[i + 3] & 0xC0) != 0x80)) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		/*
		 * Just in case, check if there's a 5th character, which is
		 * forbidden by UTF-8
		 */
		if (OF_UNLIKELY(str[i] & 0x08)) {
			madvise((void*)str, len, MADV_NORMAL);
			return -1;
		}

		i += 3;
	}

	madvise((void*)str, len, MADV_NORMAL);

	return utf8;
}

@implementation OFString
+ string
{
	return [[[OFMutableString alloc] init] autorelease];
	return [[[self alloc] init] autorelease];
}

+ stringWithCString: (const char*)str
{
	return [[[OFMutableString alloc] initWithCString: str] autorelease];
	return [[[self alloc] initWithCString: str] autorelease];
}

+ stringWithFormat: (OFString*)fmt, ...
{
	id ret;
	va_list args;

	va_start(args, fmt);
	ret = [[[OFMutableString alloc] initWithFormat: fmt
	ret = [[[self alloc] initWithFormat: fmt
					  andArguments: args] autorelease];
	va_end(args);

	return ret;
}

+ stringWithFormat: (OFString*)fmt
      andArguments: (va_list)args
{
	return [[[OFMutableString alloc] initWithFormat: fmt
	return [[[self alloc] initWithFormat: fmt
					   andArguments: args] autorelease];
}

- init
{
	[super init];

	string = NULL;

	return self;
}

- initWithCString: (const char*)str
{
	Class c;

	self = [super init];

	if (str != NULL) {
		length = strlen(str);

		switch (of_string_check_utf8(str, length)) {
			case 1:
				is_utf8 = YES;
				break;
			case -1:
				c = isa;
				[super dealloc];
				@throw [OFInvalidEncodingException
					newWithClass: c];
		}

		@try {
			string = [self allocWithSize: length + 1];
		} @catch (OFException *e) {
			/*
			 * We can't use [super dealloc] on OS X here.
			 * Compiler bug? Anyway, [self dealloc] will do here as
			 * we don't reimplement dealloc.
			 */
			[self dealloc];
			@throw e;
		}
		memcpy(string, str, length + 1);
	}

	return self;
}

- initWithFormat: (OFString*)fmt, ...
{
	id ret;
	va_list args;

	va_start(args, fmt);
	ret = [self initWithFormat: fmt
		      andArguments: args];
	va_end(args);

	return ret;
}

- initWithFormat: (OFString*)fmt
    andArguments: (va_list)args
{
	int t;
	Class c;

	self = [super init];

	if (fmt == NULL) {
		c = isa;
		[super dealloc];
		@throw [OFInvalidFormatException newWithClass: c];
	}

	if ((t = vasprintf(&string, [fmt cString], args)) == -1) {
		c = isa;
		[super dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}
	length = t;

	switch (of_string_check_utf8(string, length)) {
		case 1:
			is_utf8 = YES;
			break;
		case -1:
			free(string);
			c = isa;
			[super dealloc];
			@throw [OFInvalidEncodingException newWithClass: c];
	}

	@try {
		[self addToMemoryPool: string];
	} @catch (OFException *e) {
		free(string);
		@throw e;
	}

	return self;
}

- (const char*)cString
{
	return string;
110
111
112
113
114
115
116
117

118
119
120
121
122
123
124
281
282
283
284
285
286
287

288
289
290
291
292
293
294
295







-
+







	for (i = 0; i < length; i++)
		OF_HASH_ADD(hash, string[i]);
	OF_HASH_FINALIZE(hash);

	return hash;
}

- setTo: (const char*)str
- setToCString: (const char*)str
{
	@throw [OFNotImplementedException newWithClass: isa
					   andSelector: _cmd];
}

- append: (OFString*)str
{

Modified tests/OFString/OFString.m from [1bae449326] to [203f97552a].

53
54
55
56
57
58
59
60
61


62
63

64
65
66
67
68
69
70
71
72
73
74

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

94
95
96
97
98

99
100
101
102
103
104
105
53
54
55
56
57
58
59


60
61
62

63
64
65
66
67
68
69
70
71
72
73

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

93
94
95
96
97

98
99
100
101
102
103
104
105







-
-
+
+

-
+










-
+


















-
+




-
+







int
main()
{
	size_t i = 0;
	size_t j = 0;

	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFString *s1 = [OFString stringWithCString: "test"];
	OFString *s2 = [OFString stringWithCString: ""];
	OFString *s1 = [OFMutableString stringWithCString: "test"];
	OFString *s2 = [OFMutableString stringWithCString: ""];
	OFString *s3;
	OFString *s4 = [OFString string];
	OFString *s4 = [OFMutableString string];
	OFArray *a;

	s3 = [s1 copy];

	CHECK([s1 isEqual: s3])
	CHECK(![s1 isEqual: [[OFObject alloc] init]])
	CHECK([s1 hash] == [s3 hash])

	[s2 appendCString: "12"];
	[s2 append: @"3"];
	[s4 setTo: [s2 cString]];
	[s4 setToCString: [s2 cString]];

	CHECK(![s2 compare: s4])
	CHECK(!strcmp([[s1 append: s2] cString], "test123"))
	CHECK([s1 hash] == 0xC44F49A4)
	CHECK(strlen([s1 cString]) == [s1 length] && [s1 length] == 7)
	CHECK(!strcmp([[s1 reverse] cString], "321tset"))
	CHECK(!strcmp([[s1 upper] cString], "321TSET"))
	CHECK(!strcmp([[s1 lower] cString], "321tset"))

	/* Also clears all the memory of the returned C strings */
	[pool release];

	/* UTF-8 tests */
	CHECK_EXCEPT(s1 = [OFString stringWithCString: "\xE0\x80"],
	    OFInvalidEncodingException)
	CHECK_EXCEPT(s1 = [OFString stringWithCString: "\xF0\x80\x80\xC0"],
	    OFInvalidEncodingException)

	s1 = [OFString stringWithCString: "äöü€𝄞"];
	s1 = [OFMutableString stringWithCString: "äöü€𝄞"];
	CHECK(!strcmp([[s1 reverse] cString], "𝄞€üöä"))
	[s1 dealloc];

	/* Format tests */
	s1 = [OFString stringWithFormat: @"%s: %d", "test", 123];
	s1 = [OFMutableString stringWithFormat: @"%s: %d", "test", 123];
	CHECK(!strcmp([s1 cString], "test: 123"))

	[s1 appendWithFormat: @"%02X", 15];
	CHECK(!strcmp([s1 cString], "test: 1230F"))

	a = [@"fooXXbarXXXXbazXXXX" splitWithDelimiter: @"XX"];
	CHECK([[a object: j++] isEqual: @"foo"])