ObjFW  Check-in [d9eb7b50b3]

Overview
Comment:Add of_ascii_{to{upper,lower},is{alpha,alnum}}

These are independent of the locale and work on the ASCII character set.

Unlike the C ones, these are 8-bit safe, meaning if a character > 0x7F
is passed, is{alpha,alnum} returns false and to{upper,lower} returns the
original character.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: d9eb7b50b3eb8630b112d9108d6ffbf53d69cd606a68f1cb5d3d7a5ca2e69d27
User & Date: js on 2017-01-07 00:37:26
Other Links: manifest | tags
Context
2017-01-07
02:34
Always use "." for the decimal point check-in: 6dff0f5922 user: js tags: trunk
00:37
Add of_ascii_{to{upper,lower},is{alpha,alnum}} check-in: d9eb7b50b3 user: js tags: trunk
00:09
OFNumber: Make description locale-compatible check-in: df5e33bec7 user: js tags: trunk
Changes

Modified src/OFHTTPClient.m from [9433d07795] to [f4eacb56f1].

45
46
47
48
49
50
51
52
53
54
55
56
57
58


59
60
61
62
63
64
65
static OF_INLINE void
normalizeKey(char *str_)
{
	unsigned char *str = (unsigned char*)str_;
	bool firstLetter = true;

	while (*str != '\0') {
		if (!isalnum(*str)) {
			firstLetter = true;
			str++;
			continue;
		}

		*str = (firstLetter ? toupper(*str) : tolower(*str));



		firstLetter = false;
		str++;
	}
}

@interface OFHTTPClientResponse: OFHTTPResponse







|





|
>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
static OF_INLINE void
normalizeKey(char *str_)
{
	unsigned char *str = (unsigned char*)str_;
	bool firstLetter = true;

	while (*str != '\0') {
		if (!of_ascii_isalpha(*str)) {
			firstLetter = true;
			str++;
			continue;
		}

		*str = (firstLetter
		    ? of_ascii_toupper(*str)
		    : of_ascii_tolower(*str));

		firstLetter = false;
		str++;
	}
}

@interface OFHTTPClientResponse: OFHTTPResponse

Modified src/OFHTTPServer.m from [28126036a1] to [30505eba7a].

150
151
152
153
154
155
156
157
158
159
160
161
162
163


164
165
166
167
168
169
170
	bool firstLetter = true;

	if (cString == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithRequestedSize: strlen([key UTF8String])];

	while (*tmp != '\0') {
		if (!isalnum(*tmp)) {
			firstLetter = true;
			tmp++;
			continue;
		}

		*tmp = (firstLetter ? toupper(*tmp) : tolower(*tmp));



		firstLetter = false;
		tmp++;
	}

	return [OFString stringWithUTF8StringNoCopy: cString
				       freeWhenDone: true];







|





|
>
>







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
	bool firstLetter = true;

	if (cString == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithRequestedSize: strlen([key UTF8String])];

	while (*tmp != '\0') {
		if (!of_ascii_isalpha(*tmp)) {
			firstLetter = true;
			tmp++;
			continue;
		}

		*tmp = (firstLetter
		    ? of_ascii_toupper(*tmp)
		    : of_ascii_tolower(*tmp));

		firstLetter = false;
		tmp++;
	}

	return [OFString stringWithUTF8StringNoCopy: cString
				       freeWhenDone: true];

Modified src/OFIntrospection.m from [5bbbc65fa4] to [0aa9a039cb].

272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
			_getter = [_name copy];

		if ((_attributes & OF_PROPERTY_READWRITE) && _setter == nil) {
			of_unichar_t first = [_name characterAtIndex: 0];
			OFMutableString *tmp = [_name mutableCopy];
			_setter = tmp;

			if (first < 0x80) {
				[tmp setCharacter: toupper((unsigned char)first)
					  atIndex: 0];
			}

			[tmp prependString: @"set"];

			[tmp makeImmutable];
		}
	} @catch (id e) {
		[self release];
		@throw e;







<
|
|
<
<







272
273
274
275
276
277
278

279
280


281
282
283
284
285
286
287
			_getter = [_name copy];

		if ((_attributes & OF_PROPERTY_READWRITE) && _setter == nil) {
			of_unichar_t first = [_name characterAtIndex: 0];
			OFMutableString *tmp = [_name mutableCopy];
			_setter = tmp;


			[tmp setCharacter: of_ascii_toupper(first)
				  atIndex: 0];


			[tmp prependString: @"set"];

			[tmp makeImmutable];
		}
	} @catch (id e) {
		[self release];
		@throw e;

Modified src/OFMutableString.m from [29e52abbc7] to [3b4d8b06cc].

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
#import "of_asprintf.h"
#import "unicode.h"

static struct {
	Class isa;
} placeholder;

#ifndef OF_HAVE_UNICODE_TABLES
/* Wrap these, as they can be macros. */
static int
toupperWrapper(int c)
{
	return toupper(c);
}

static int
tolowerWrapper(int c)
{
	return tolower(c);
}
#endif

@interface OFMutableString_placeholder: OFMutableString
@end

@implementation OFMutableString_placeholder
- init
{
	return (id)[[OFMutableString_UTF8 alloc] init];







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







33
34
35
36
37
38
39















40
41
42
43
44
45
46
#import "of_asprintf.h"
#import "unicode.h"

static struct {
	Class isa;
} placeholder;
















@interface OFMutableString_placeholder: OFMutableString
@end

@implementation OFMutableString_placeholder
- init
{
	return (id)[[OFMutableString_UTF8 alloc] init];
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
			break;
		}
	}

	objc_autoreleasePoolPop(pool);
}
#else
- (void)OF_convertWithWordStartFunction: (int (*)(int))startFunction
		     wordMiddleFunction: (int (*)(int))middleFunction
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t length = [self length];
	bool isStart = true;

	for (size_t i = 0; i < length; i++) {
		int (*function)(int) =
		    (isStart ? startFunction : middleFunction);;
		of_unichar_t c = characters[i];

		if (c <= 0x7F)
			[self setCharacter: (int)function(c)
				   atIndex: i];








|
|







|







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
			break;
		}
	}

	objc_autoreleasePoolPop(pool);
}
#else
- (void)OF_convertWithWordStartFunction: (char (*)(char))startFunction
		     wordMiddleFunction: (char (*)(char))middleFunction
{
	void *pool = objc_autoreleasePoolPush();
	const of_unichar_t *characters = [self characters];
	size_t length = [self length];
	bool isStart = true;

	for (size_t i = 0; i < length; i++) {
		char (*function)(char) =
		    (isStart ? startFunction : middleFunction);;
		of_unichar_t c = characters[i];

		if (c <= 0x7F)
			[self setCharacter: (int)function(c)
				   atIndex: i];

480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
			   wordMiddleTable: of_unicode_lowercase_table
			wordStartTableSize: OF_UNICODE_TITLECASE_TABLE_SIZE
		       wordMiddleTableSize: OF_UNICODE_LOWERCASE_TABLE_SIZE];
}
#else
- (void)uppercase
{
	[self OF_convertWithWordStartFunction: toupperWrapper
			   wordMiddleFunction: toupperWrapper];
}

- (void)lowercase
{
	[self OF_convertWithWordStartFunction: tolowerWrapper
			   wordMiddleFunction: tolowerWrapper];
}

- (void)capitalize
{
	[self OF_convertWithWordStartFunction: toupperWrapper
			   wordMiddleFunction: tolowerWrapper];
}
#endif

- (void)insertString: (OFString*)string
	     atIndex: (size_t)index
{
	[self replaceCharactersInRange: of_range(index, 0)







|
|




|
|




|
|







465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
			   wordMiddleTable: of_unicode_lowercase_table
			wordStartTableSize: OF_UNICODE_TITLECASE_TABLE_SIZE
		       wordMiddleTableSize: OF_UNICODE_LOWERCASE_TABLE_SIZE];
}
#else
- (void)uppercase
{
	[self OF_convertWithWordStartFunction: of_ascii_toupper
			   wordMiddleFunction: of_ascii_toupper];
}

- (void)lowercase
{
	[self OF_convertWithWordStartFunction: of_ascii_tolower
			   wordMiddleFunction: of_ascii_tolower];
}

- (void)capitalize
{
	[self OF_convertWithWordStartFunction: of_ascii_toupper
			   wordMiddleFunction: of_ascii_tolower];
}
#endif

- (void)insertString: (OFString*)string
	     atIndex: (size_t)index
{
	[self replaceCharactersInRange: of_range(index, 0)

Modified src/OFObject+KeyValueCoding.m from [3eca7b4ec4] to [3802a76383].

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
			    exceptionWithRequestedSize: keyLength + 3];

		@try {
			memcpy(name, "is", 2);
			memcpy(name + 2, [key UTF8String], keyLength);
			name[keyLength + 2] = '\0';

			name[2] = toupper((unsigned char)name[2]);

			selector = sel_registerName(name);
		} @finally {
			free(name);
		}

		typeEncoding = [self typeEncodingForSelector: selector];







|







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
			    exceptionWithRequestedSize: keyLength + 3];

		@try {
			memcpy(name, "is", 2);
			memcpy(name + 2, [key UTF8String], keyLength);
			name[keyLength + 2] = '\0';

			name[2] = of_ascii_toupper(name[2]);

			selector = sel_registerName(name);
		} @finally {
			free(name);
		}

		typeEncoding = [self typeEncodingForSelector: selector];
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
		    exceptionWithRequestedSize: keyLength + 5];

	@try {
		memcpy(name, "set", 3);
		memcpy(name + 3, [key UTF8String], keyLength);
		memcpy(name + keyLength + 3, ":", 2);

		name[3] = toupper((unsigned char)name[3]);

		selector = sel_registerName(name);
	} @finally {
		free(name);
	}

	typeEncoding = [self typeEncodingForSelector: selector];







|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
		    exceptionWithRequestedSize: keyLength + 5];

	@try {
		memcpy(name, "set", 3);
		memcpy(name + 3, [key UTF8String], keyLength);
		memcpy(name + keyLength + 3, ":", 2);

		name[3] = of_ascii_toupper(name[3]);

		selector = sel_registerName(name);
	} @finally {
		free(name);
	}

	typeEncoding = [self typeEncodingForSelector: selector];

Modified src/OFString+URLEncoding.m from [9b57fed9b2] to [6c61b62a6b].

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
		unsigned char c = *string;

		/*
		 * '+' is also listed in RFC 1738, however, '+' is sometimes
		 * interpreted as space in HTTP. Therefore always escape it to
		 * make sure it's always interpreted correctly.
		 */
		if (!(c & 0x80) && (isalnum(c) || strchr(allowed, c) != NULL))
			retCString[i++] = c;
		else {
			unsigned char high, low;

			high = c >> 4;
			low = c & 0x0F;








|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
		unsigned char c = *string;

		/*
		 * '+' is also listed in RFC 1738, however, '+' is sometimes
		 * interpreted as space in HTTP. Therefore always escape it to
		 * make sure it's always interpreted correctly.
		 */
		if (of_ascii_isalnum(c) || strchr(allowed, c) != NULL)
			retCString[i++] = c;
		else {
			unsigned char high, low;

			high = c >> 4;
			low = c & 0x0F;

Modified src/OFString.m from [d7680287a6] to [4bcce6446e].

1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
			of_unichar_t tc =
			    of_unicode_casefolding_table[oc >> 8][oc & 0xFF];

			if (tc)
				oc = tc;
		}
#else
		if (c <= 0x7F)
			c = toupper(c);
		if (oc <= 0x7F)
			oc = toupper(oc);
#endif

		if (c > oc) {
			objc_autoreleasePoolPop(pool);
			return OF_ORDERED_DESCENDING;
		}
		if (c < oc) {







<
|
<
|







1369
1370
1371
1372
1373
1374
1375

1376

1377
1378
1379
1380
1381
1382
1383
1384
			of_unichar_t tc =
			    of_unicode_casefolding_table[oc >> 8][oc & 0xFF];

			if (tc)
				oc = tc;
		}
#else

		c = of_ascii_toupper(c);

		oc = of_ascii_toupper(oc);
#endif

		if (c > oc) {
			objc_autoreleasePoolPop(pool);
			return OF_ORDERED_DESCENDING;
		}
		if (c < oc) {

Modified src/OFString_UTF8.m from [539d29c205] to [b0d3c841b5].

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
static inline int
memcasecmp(const char *first, const char *second, size_t length)
{
	for (size_t i = 0; i < length; i++) {
		unsigned char f = first[i];
		unsigned char s = second[i];

		if (f <= 0x7F)
			f = toupper(f);
		if (s <= 0x7F)
			s = toupper(s);

		if (f > s)
			return OF_ORDERED_DESCENDING;
		if (f < s)
			return OF_ORDERED_ASCENDING;
	}








<
|
<
|







45
46
47
48
49
50
51

52

53
54
55
56
57
58
59
60
static inline int
memcasecmp(const char *first, const char *second, size_t length)
{
	for (size_t i = 0; i < length; i++) {
		unsigned char f = first[i];
		unsigned char s = second[i];


		f = of_ascii_toupper(f);

		s = of_ascii_toupper(s);

		if (f > s)
			return OF_ORDERED_DESCENDING;
		if (f < s)
			return OF_ORDERED_ASCENDING;
	}

777
778
779
780
781
782
783
784



785
786
787
788
789
790
791
	else
		return OF_ORDERED_ASCENDING;
}

- (of_comparison_result_t)caseInsensitiveCompare: (OFString*)otherString
{
	const char *otherCString;
	size_t i, j, otherCStringLength, minimumCStringLength;



	int compare;

	if (otherString == self)
		return OF_ORDERED_SAME;

	if (![otherString isKindOfClass: [OFString class]])
		@throw [OFInvalidArgumentException exception];







|
>
>
>







775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
	else
		return OF_ORDERED_ASCENDING;
}

- (of_comparison_result_t)caseInsensitiveCompare: (OFString*)otherString
{
	const char *otherCString;
	size_t otherCStringLength, minimumCStringLength;
#ifdef OF_HAVE_UNICODE_TABLES
	size_t i, j;
#endif
	int compare;

	if (otherString == self)
		return OF_ORDERED_SAME;

	if (![otherString isKindOfClass: [OFString class]])
		@throw [OFInvalidArgumentException exception];
849
850
851
852
853
854
855
856
857
858
859
860
861

862
863
864
865
866
867
868
			return OF_ORDERED_DESCENDING;
		if (c1 < c2)
			return OF_ORDERED_ASCENDING;

		i += l1;
		j += l2;
	}
#endif

	if (_s->cStringLength - i > otherCStringLength - j)
		return OF_ORDERED_DESCENDING;
	else if (_s->cStringLength - i < otherCStringLength - j)
		return OF_ORDERED_ASCENDING;


	return OF_ORDERED_SAME;
}

- (uint32_t)hash
{
	uint32_t hash;







<





>







850
851
852
853
854
855
856

857
858
859
860
861
862
863
864
865
866
867
868
869
			return OF_ORDERED_DESCENDING;
		if (c1 < c2)
			return OF_ORDERED_ASCENDING;

		i += l1;
		j += l2;
	}


	if (_s->cStringLength - i > otherCStringLength - j)
		return OF_ORDERED_DESCENDING;
	else if (_s->cStringLength - i < otherCStringLength - j)
		return OF_ORDERED_ASCENDING;
#endif

	return OF_ORDERED_SAME;
}

- (uint32_t)hash
{
	uint32_t hash;

Modified src/OFURL.m from [6c7fd6999e] to [cbd9a32b8b].

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

		UTF8String = UTF8String2;

		if ((tmp = strstr(UTF8String, "://")) == NULL)
			@throw [OFInvalidFormatException exception];

		for (tmp2 = UTF8String; tmp2 < tmp; tmp2++)
			*tmp2 = tolower((unsigned char)*tmp2);

		_scheme = [[OFString alloc]
		    initWithUTF8String: UTF8String
				length: tmp - UTF8String];

		UTF8String = tmp + 3;








|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

		UTF8String = UTF8String2;

		if ((tmp = strstr(UTF8String, "://")) == NULL)
			@throw [OFInvalidFormatException exception];

		for (tmp2 = UTF8String; tmp2 < tmp; tmp2++)
			*tmp2 = of_ascii_tolower(*tmp2);

		_scheme = [[OFString alloc]
		    initWithUTF8String: UTF8String
				length: tmp - UTF8String];

		UTF8String = tmp + 3;

Modified src/macros.h from [63bde433c3] to [49ab80b017].

605
606
607
608
609
610
611
























of_explicit_memset(void *buffer_, int character, size_t length)
{
	volatile unsigned char *buffer = buffer_;

	while (buffer < (unsigned char*)buffer_ + length)
		*buffer++ = character;
}































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
of_explicit_memset(void *buffer_, int character, size_t length)
{
	volatile unsigned char *buffer = buffer_;

	while (buffer < (unsigned char*)buffer_ + length)
		*buffer++ = character;
}

static OF_INLINE bool
of_ascii_isalpha(char c)
{
	return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
}

static OF_INLINE bool
of_ascii_isalnum(char c)
{
	return (of_ascii_isalpha(c) || (c >= '0' && c <= '9'));
}

static OF_INLINE char
of_ascii_toupper(char c)
{
	return (c >= 'a' && c <= 'z' ? 'A' + (c - 'a') : c);
}

static OF_INLINE char
of_ascii_tolower(char c)
{
	return (c >= 'A' && c <= 'Z' ? 'a' + (c - 'A') : c);
}