ObjFW  Diff

Differences From Artifact [76ddc597a2]:

To Artifact [8b1cd7f8e8]:


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
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







-
+






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

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







+

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


-
+











-

+


-
+

-
+
-
-








#include <stdlib.h>
#include <ctype.h>

#import "OFObject.h"
#import "OFObject+KeyValueCoding.h"
#import "OFString.h"
#import "OFNull.h"
#import "OFNumber.h"

#import "OFOutOfMemoryException.h"
#import "OFUndefinedKeyException.h"

int _OFObject_KeyValueCoding_reference;

static bool
static char OF_INLINE
checkTypeEncoding(const char *typeEncoding, char returnType, ...)
{
	va_list args;
	char type;

	if (typeEncoding == NULL)
		return false;

	if (*typeEncoding++ != returnType)
		return false;

	while (*typeEncoding >= '0' && *typeEncoding <= '9')
		typeEncoding++;

nextType(const char **typeEncoding)
{
	va_start(args, returnType);

	while ((type = va_arg(args, int)) != 0) {
		if (*typeEncoding++ != type)
	char ret = *(*typeEncoding)++;
			return false;

		while (*typeEncoding >= '0' && *typeEncoding <= '9')
			typeEncoding++;
	}
	while (**typeEncoding >= '0' && **typeEncoding <= '9')
		(*typeEncoding)++;


	if (*typeEncoding != '\0')
		return false;
	return ret;

	return true;
}

@implementation OFObject (KeyValueCoding)
- (id)valueForKey: (OFString*)key
{
	SEL selector = sel_registerName([key UTF8String]);
	const char *typeEncoding = [self typeEncodingForSelector: selector];
	id ret;

	switch (nextType(&typeEncoding)) {
	case '@':
		ret = [self performSelector: selector];
		break;
#define CASE(encoding, type, method)					  \
	case encoding:							  \
		{							  \
			type (*getter)(id, SEL) = (type(*)(id, SEL))	  \
			    [self methodForSelector: selector];		  \
			ret = [OFNumber method getter(self, selector)]; \
		}							  \
		break;
	CASE('B', bool, numberWithBool:)
	CASE('c', char, numberWithChar:)
	CASE('s', short, numberWithShort:)
	CASE('i', int, numberWithInt:)
	CASE('l', long, numberWithLong:)
	CASE('q', long long, numberWithLongLong:)
	CASE('C', unsigned char, numberWithUnsignedChar:)
	CASE('S', unsigned short, numberWithUnsignedShort:)
	CASE('I', unsigned int, numberWithUnsignedInt:)
	CASE('L', unsigned long, numberWithUnsignedLong:)
	CASE('Q', unsigned long long, numberWithUnsignedLongLong:)
	CASE('f', float, numberWithFloat:)
	CASE('d', double, numberWithDouble:)
#undef CASE
	default:
		return [self valueForUndefinedKey: key];
	}
	if (!checkTypeEncoding(typeEncoding, '@', '@', ':', 0))

	if (nextType(&typeEncoding) != '@' || nextType(&typeEncoding) != ':' ||
	    *typeEncoding != 0)
		return [self valueForUndefinedKey: key];

	return [self performSelector: selector];
	return ret;
}

- (id)valueForUndefinedKey: (OFString*)key
{
	@throw [OFUndefinedKeyException exceptionWithObject: self
							key: key];
}

- (void)setValue: (id)value
	  forKey: (OFString*)key
{
	char *name;
	size_t keyLength;
	char *name;
	SEL selector;
	const char *typeEncoding;
	id (*setter)(id, SEL, id);
	char valueType;

	keyLength = [key UTF8StringLength];
	if ((keyLength = [key UTF8StringLength]) < 1) {

	if (keyLength < 1) {
		[self	 setValue: value
		  forUndefinedKey: key];
		return;
	}

	if ((name = malloc(keyLength + 5)) == NULL)
		@throw [OFOutOfMemoryException
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
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







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




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











	selector = sel_registerName(name);

	free(name);

	typeEncoding = [self typeEncodingForSelector: selector];

	if (nextType(&typeEncoding) != 'v' || nextType(&typeEncoding) != '@' ||
	    nextType(&typeEncoding) != ':') {
		[self    setValue: value
		  forUndefinedKey: key];
		return;
	}
	if (!checkTypeEncoding(typeEncoding, 'v', '@', ':', '@', 0)) {
		[self	 setValue: value

	valueType = nextType(&typeEncoding);

	if (*typeEncoding != 0) {
		[self    setValue: value
		  forUndefinedKey: key];
		return;
	}

	switch (valueType) {
	case '@':
		{
			void (*setter)(id, SEL, id) = (void(*)(id, SEL, id))
	setter = (id(*)(id, SEL, id))[self methodForSelector: selector];
	setter(self, selector, value);
			    [self methodForSelector: selector];
			setter(self, selector, value);
		}
		break;
#define CASE(encoding, type, method) \
	case encoding:						\
		{						\
			void (*setter)(id, SEL, type) =		\
			    (void(*)(id, SEL, type))		\
			    [self methodForSelector: selector];	\
			setter(self, selector, [value method]);	\
		}						\
		break;
	CASE('B', bool, boolValue)
	CASE('c', char, charValue)
	CASE('s', short, shortValue)
	CASE('i', int, intValue)
	CASE('l', long, longValue)
	CASE('q', long long, longLongValue)
	CASE('C', unsigned char, unsignedCharValue)
	CASE('S', unsigned short, unsignedShortValue)
	CASE('I', unsigned int, unsignedIntValue)
	CASE('L', unsigned long, unsignedLongValue)
	CASE('Q', unsigned long long, unsignedLongLongValue)
	CASE('f', float, floatValue)
	CASE('d', double, doubleValue)
#undef CASE
	default:
		[self    setValue: value
		  forUndefinedKey: key];
		return;
	}
}

-  (void)setValue: (id)value
  forUndefinedKey: (OFString*)key
{
	@throw [OFUndefinedKeyException exceptionWithObject: self
							key: key
						      value: value];
}
@end