]> err.no Git - sope/blob - sope-appserver/NGObjWeb/NSObject+WO.m
fixed copyrights for 2005
[sope] / sope-appserver / NGObjWeb / NSObject+WO.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "NSObject+WO.h"
23 #include "common.h"
24
25 #if APPLE_RUNTIME || NeXT_RUNTIME
26 #  include <objc/objc-class.h>
27 #endif
28
29 #if NeXT_Foundation_LIBRARY || APPLE_FOUNDATION_LIBRARY || \
30     COCOA_Foundation_LIBRARY
31
32 #ifndef __APPLE__
33 @implementation NSObject(FoundationCompability)
34
35 - (id)copyWithZone:(NSZone *)_z {
36   return [self retain];
37 }
38
39 @end /* NSObject(FoundationCompability) */
40 #endif
41
42 #endif /* NeXT_Foundation_LIBRARY */
43
44 #if GNUSTEP_BASE_LIBRARY
45 extern BOOL __objc_responds_to(id, SEL);
46 #endif
47
48 @implementation NSObject(NGObjWebKVC)
49
50 - (BOOL)kvcIsPreferredInKeyPath {
51   return NO;
52 }
53
54 @end /* NSObject(NGObjWebKVC) */
55
56 @implementation NSDictionary(NGObjWebKVC)
57
58 - (BOOL)kvcIsPreferredInKeyPath {
59   return YES;
60 }
61
62 @end /* NSDictionary(NGObjWebKVC) */
63
64 @implementation NSObject(Faults)
65 #ifndef __APPLE__
66 + (BOOL)isFault {
67   return NO;
68 }
69 - (BOOL)isFault {
70   return NO;
71 }
72 #endif
73 @end /* NSObject(Faults) */
74
75 // ******************** KVC methods ********************
76
77 static inline void _getSetSelName(register unsigned char *buf,
78                                   register const unsigned char *_key,
79                                   register unsigned _len) {
80   buf[0] = 's';
81   buf[1] = 'e';
82   buf[2] = 't';
83
84   switch (_len) {
85     case 0: break;
86
87     case 1:
88       buf[3] = _key[0];
89       break;
90     case 2:
91       buf[3] = _key[0];
92       buf[4] = _key[1];
93       break;
94     case 3:
95       buf[3] = _key[0];
96       buf[4] = _key[1];
97       buf[5] = _key[2];
98       break;
99     case 4:
100       buf[3] = _key[0];
101       buf[4] = _key[1];
102       buf[5] = _key[2];
103       buf[6] = _key[3];
104       break;
105     case 5:
106       buf[3] = _key[0];
107       buf[4] = _key[1];
108       buf[5] = _key[2];
109       buf[6] = _key[3];
110       buf[7] = _key[4];
111       break;
112     case 6:
113       buf[3] = _key[0];
114       buf[4] = _key[1];
115       buf[5] = _key[2];
116       buf[6] = _key[3];
117       buf[7] = _key[4];
118       buf[8] = _key[5];
119       break;
120       
121     default:
122       memcpy(&(buf[3]), _key, _len);
123       break;
124   }
125   buf[3] = toupper(buf[3]);
126   buf[_len + 3] = ':';
127   buf[_len + 4] = '\0';
128 }
129 static inline SEL _getSetSel(register const unsigned char *_key,
130                              register unsigned _len) {
131   char buf[259];
132   _getSetSelName(buf, _key, _len);
133 #if APPLE_RUNTIME || NeXT_RUNTIME
134   return sel_getUid(buf);
135 #else
136   return sel_get_uid(buf);
137 #endif
138 }
139
140 typedef union {
141   IMP            method; // real method or takeValue:ForKey:
142   char           (*cmethod) (id, SEL);
143   unsigned char  (*ucmethod)(id, SEL);
144   int            (*imethod) (id, SEL);
145   unsigned int   (*uimethod)(id, SEL);
146   short          (*smethod) (id, SEL);
147   unsigned short (*usmethod)(id, SEL);
148   const char *   (*strmethod)(id, SEL);
149   float          (*fmethod)(id, SEL);
150   double         (*dmethod)(id, SEL);
151 } WOGetMethodType;
152
153 typedef union {
154   IMP  method; // real method or takeValue:ForKey:
155   void (*omethod)  (id, SEL, id);
156   void (*cmethod)  (id, SEL, char);
157   void (*ucmethod) (id, SEL, unsigned char);
158   void (*imethod)  (id, SEL, int);
159   void (*uimethod) (id, SEL, unsigned int);
160   void (*smethod)  (id, SEL, short);
161   void (*usmethod) (id, SEL, unsigned short);
162   void (*strmethod)(id, SEL, const char *);
163   void (*fmethod)  (id, SEL, float);
164   void (*dmethod)  (id, SEL, double);
165 } WOSetMethodType;
166
167 BOOL WOSetKVCValueUsingMethod(id object, NSString *_key, id _value) {
168   NSMethodSignature *sig = nil;
169   WOSetMethodType   sm;
170   const char        *argType;
171   SEL               setSel;
172   unsigned          keyLen;
173   char              *buf;
174   
175   if (object == nil) return NO;
176   if (_key   == nil) return NO;
177
178   keyLen = [_key cStringLength];
179   
180   buf = malloc(keyLen + 2);
181   [_key getCString:buf];
182   setSel = _getSetSel(buf, keyLen);
183   free(buf); buf = NULL;
184   
185   if (setSel == NULL) // no such selector
186     return NO;
187
188   sig = [object methodSignatureForSelector:setSel];
189   if (sig == nil) // no signature
190     return NO;
191   
192   sm.method = [object methodForSelector:setSel];
193   if (sm.method) {
194     argType = [sig getArgumentTypeAtIndex:2];
195     
196     switch (*argType) {
197       case _C_CLASS:
198       case _C_ID:
199         sm.omethod(object, setSel, _value);
200         break;
201
202       case _C_CHR:
203         sm.cmethod(object, setSel, [(NSValue *)_value charValue]);
204         break;
205       case _C_UCHR:
206         sm.ucmethod(object, setSel, [_value unsignedCharValue]);
207         break;
208
209       case _C_SHT:
210         sm.smethod(object, setSel, [_value shortValue]);
211         break;
212       case _C_USHT:
213         sm.usmethod(object, setSel, [_value unsignedShortValue]);
214         break;
215             
216       case _C_INT:
217         sm.imethod(object, setSel, [_value intValue]);
218         break;
219       case _C_UINT:
220         sm.uimethod(object, setSel, [_value unsignedIntValue]);
221         break;
222         
223       case _C_FLT:
224         sm.fmethod(object, setSel, [_value floatValue]);
225         break;
226         
227       case _C_DBL:
228         sm.dmethod(object, setSel, [_value doubleValue]);
229         break;
230
231       case _C_CHARPTR: {
232         char *s;
233         s = NGMallocAtomic([_value cStringLength] + 1);
234         [_value getCString:s];
235         sm.strmethod(object, setSel, s);
236         NGFree(s); s = NULL;
237         break;
238       }
239       
240       default:
241         NSLog(@"%s: cannot set type '%c' yet (key=%@, method=%@) ..",
242               __PRETTY_FUNCTION__,
243               *argType, _key, NSStringFromSelector(setSel));
244         [NSException raise:@"WORuntimeException"
245                      format:@"cannot set type '%c' yet (key=%@, method=%@)",
246                        *argType, _key, NSStringFromSelector(setSel)];
247         return NO;
248     }
249     return YES;
250   }
251   else // did not find method
252     return NO;
253 }
254
255 IMP WOGetKVCGetMethod(id object, NSString *_key) {
256   register SEL getSel;
257   
258   if (object == nil) return NULL;
259   if (_key   == nil) return NULL;
260
261 #if GNU_RUNTIME
262   {
263     unsigned keyLen;
264     char     *buf;
265     
266     keyLen = [_key cStringLength];
267     buf = malloc(keyLen + 1);
268     [_key getCString:buf]; buf[keyLen] = '\0';
269     getSel = sel_get_uid(buf);
270     free(buf);
271
272     if (getSel == NULL) // no such selector
273       return NULL;
274 #if GNUSTEP_BASE_LIBRARY
275     if (!__objc_responds_to(object, getSel))
276       return NULL;
277 #endif
278
279     return [object methodForSelector:getSel];
280   }
281 #else
282   if ((getSel = NSSelectorFromString(_key)) == NULL) // no such selector
283     return NULL;
284
285   if ([object respondsToSelector:getSel])
286     return [object methodForSelector:getSel];
287
288   return NULL;
289 #endif
290 }
291
292 id WOGetKVCValueUsingMethod(id object, NSString *_key) {
293   NSMethodSignature *sig = nil;
294   WOGetMethodType   gm;
295   const char        *retType;
296   SEL               getSel;
297   unsigned          keyLen;
298   
299   if (object == nil) return nil;
300   if (_key   == nil) return nil;
301   
302   // TODO: this su***
303   // TODO: add support for ivars
304   keyLen = [_key cStringLength];
305
306   {
307     char *buf;
308     buf = malloc(keyLen + 1);
309     [_key getCString:buf];
310 #if APPLE_RUNTIME || NeXT_RUNTIME
311     getSel = sel_getUid(buf);
312 #else
313     getSel = sel_get_uid(buf);
314 #endif
315     if (getSel == NULL) // no such selector
316       return nil;
317     free(buf); buf = NULL;
318   }
319 #if GNUSTEP_BASE_LIBRARY
320   if (!__objc_responds_to(object, getSel))
321     return nil;
322 #endif
323   
324   gm.method = [object methodForSelector:getSel];
325   if (gm.method == NULL) // no such method
326     return nil;
327   
328   sig = [object methodSignatureForSelector:getSel];
329   if (sig == nil) // no signature
330     return nil;
331
332   {
333     static Class NSNumberClass = Nil;
334     id value = nil;
335
336     if (NSNumberClass == Nil)
337       NSNumberClass = [NSNumber class];
338     
339     retType = [sig methodReturnType];
340     
341     switch (*retType) {
342       case _C_CLASS:
343       case _C_ID:
344         value = gm.method(object, getSel);
345         value = AUTORELEASE(RETAIN(value));
346         break;
347
348       case _C_CHR:
349         value = [NSNumberClass numberWithChar:gm.cmethod(object, getSel)];
350         break;
351       case _C_UCHR:
352         value = [NSNumberClass numberWithUnsignedChar:
353                                  gm.ucmethod(object, getSel)];
354         break;
355
356       case _C_SHT:
357         value = [NSNumberClass numberWithShort:gm.smethod(object, getSel)];
358         break;
359       case _C_USHT:
360         value = [NSNumberClass numberWithUnsignedShort:
361                                  gm.usmethod(object, getSel)];
362         break;
363             
364       case _C_INT:
365         value = [NSNumberClass numberWithInt:gm.imethod(object, getSel)];
366         break;
367       case _C_UINT:
368         value = [NSNumberClass numberWithUnsignedInt:
369                                  gm.uimethod(object, getSel)];
370         break;
371
372       case _C_FLT:
373         value = [NSNumberClass numberWithFloat:gm.fmethod(object, getSel)];
374         break;
375       case _C_DBL:
376         value = [NSNumberClass numberWithDouble:gm.dmethod(object, getSel)];
377         break;
378         
379       case _C_CHARPTR: {
380         const char *cstr = gm.strmethod(object, getSel);
381         value = cstr ? [NSString stringWithCString:cstr] : nil;
382         break;
383       }
384             
385       default:
386         NSLog(@"%s: cannot get type '%c' yet (key=%@, method=%@) ..",
387               __PRETTY_FUNCTION__,
388               *retType, _key, NSStringFromSelector(getSel));
389         [NSException raise:@"WORuntimeException"
390                      format:@"cannot get type '%c' yet (key=%@, method=%@)",
391                        *retType, _key, NSStringFromSelector(getSel)];
392         return nil;
393     }
394     return value;
395   }
396 }