]> err.no Git - sope/blob - sope-core/EOControl/EOKeyValueCoding.m
Xcode project
[sope] / sope-core / EOControl / EOKeyValueCoding.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo 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   OGo 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 OGo; 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 // $Id$
22
23 #include "EOKeyValueCoding.h"
24 #include "EONull.h"
25 #include "common.h"
26
27 #if GNU_RUNTIME
28 #  include <objc/objc-api.h>
29 #  include <objc/encoding.h>
30 #endif
31
32 static EONull *null = nil;
33
34 #if !NeXT_Foundation_LIBRARY
35
36 static id idMethodGetFunc(void* info1, void* info2, id self);
37 static id idIvarGetFunc(void* info1, void* info2, id self);
38 static void idMethodSetFunc(void* info1, void* info2, id self, id val);
39 static void idIvarSetFunc(void* info1, void* info2, id self, id val);
40 static id charMethodGetFunc(void* info1, void* info2, id self);
41 static id charIvarGetFunc(void* info1, void* info2, id self);
42 static void charMethodSetFunc(void* info1, void* info2, id self, id val);
43 static void charIvarSetFunc(void* info1, void* info2, id self, id val);
44 static id unsignedCharMethodGetFunc(void* info1, void* info2, id self);
45 static id unsignedCharIvarGetFunc(void* info1, void* info2, id self);
46 static void unsignedCharMethodSetFunc(void* info1, void* info2, id self, id val);
47 static void unsignedCharIvarSetFunc(void* info1, void* info2, id self, id val);
48 static id shortMethodGetFunc(void* info1, void* info2, id self);
49 static id shortIvarGetFunc(void* info1, void* info2, id self);
50 static void shortMethodSetFunc(void* info1, void* info2, id self, id val);
51 static void shortIvarSetFunc(void* info1, void* info2, id self, id val);
52 static id unsignedShortMethodGetFunc(void* info1, void* info2, id self);
53 static id unsignedShortIvarGetFunc(void* info1, void* info2, id self);
54 static void unsignedShortMethodSetFunc(void* info1, void* info2, id self, id val);
55 static void unsignedShortIvarSetFunc(void* info1, void* info2, id self, id val);
56 static id intMethodGetFunc(void* info1, void* info2, id self);
57 static id intIvarGetFunc(void* info1, void* info2, id self);
58 static void intMethodSetFunc(void* info1, void* info2, id self, id val);
59 static void intIvarSetFunc(void* info1, void* info2, id self, id val);
60 static id unsignedIntMethodGetFunc(void* info1, void* info2, id self);
61 static id unsignedIntIvarGetFunc(void* info1, void* info2, id self);
62 static void unsignedIntMethodSetFunc(void* info1, void* info2, id self, id val);
63 static void unsignedIntIvarSetFunc(void* info1, void* info2, id self, id val);
64 static id longMethodGetFunc(void* info1, void* info2, id self);
65 static id longIvarGetFunc(void* info1, void* info2, id self);
66 static void longMethodSetFunc(void* info1, void* info2, id self, id val);
67 static void longIvarSetFunc(void* info1, void* info2, id self, id val);
68 static id unsignedLongMethodGetFunc(void* info1, void* info2, id self);
69 static id unsignedLongIvarGetFunc(void* info1, void* info2, id self);
70 static void unsignedLongMethodSetFunc(void* info1, void* info2, id self, id val);
71 static void unsignedLongIvarSetFunc(void* info1, void* info2, id self, id val);
72 static id longLongMethodGetFunc(void* info1, void* info2, id self);
73 static id longLongIvarGetFunc(void* info1, void* info2, id self);
74 static void longLongMethodSetFunc(void* info1, void* info2, id self, id val);
75 static void longLongIvarSetFunc(void* info1, void* info2, id self, id val);
76 static id unsignedLongLongMethodGetFunc(void* info1, void* info2, id self);
77 static id unsignedLongLongIvarGetFunc(void* info1, void* info2, id self);
78 static void unsignedLongLongMethodSetFunc(void* info1, void* info2, id self, id val);
79 static void unsignedLongLongIvarSetFunc(void* info1, void* info2, id self, id val);
80 static id floatMethodGetFunc(void* info1, void* info2, id self);
81 static id floatIvarGetFunc(void* info1, void* info2, id self);
82 static void floatMethodSetFunc(void* info1, void* info2, id self, id val);
83 static void floatIvarSetFunc(void* info1, void* info2, id self, id val);
84 static id doubleMethodGetFunc(void* info1, void* info2, id self);
85 static id doubleIvarGetFunc(void* info1, void* info2, id self);
86 static void doubleMethodSetFunc(void* info1, void* info2, id self, id val);
87 static void doubleIvarSetFunc(void* info1, void* info2, id self, id val);
88
89 static Class NumberClass = Nil;
90 static Class StringClass = Nil;
91
92 @implementation NSObject(EOKeyValueCoding)
93
94 /*
95  *  Types
96  */
97
98 typedef struct _KeyValueMethod {
99   NSString*   key;
100   Class       class;
101 } KeyValueMethod;
102
103 typedef struct _GetKeyValueBinding {
104   /* info1, info2, self */
105   id (*access)(void *, void *, id);
106   void *info1;
107   void *info2;
108 } GetKeyValueBinding;
109
110 typedef struct _SetKeyValueBinding {
111   /* info1, info2, self, val */
112   void (*access)(void *, void *, id, id);
113   void *info1;
114   void *info2;
115 } SetKeyValueBinding;
116
117 /*
118  * Globals
119  */
120
121 static NSMapTable* getValueBindings = NULL;
122 static NSMapTable* setValueBindings = NULL;
123 static BOOL keyValueDebug = NO;
124 static BOOL keyValueInit  = NO;
125
126 /*
127  *  KeyValueMapping
128  */
129
130 static GetKeyValueBinding* newGetBinding(NSString* key, id instance)
131 {
132   GetKeyValueBinding *ret = NULL;
133   void *info1 = NULL;
134   void *info2 = NULL;
135   id (*fptr)(void*, void*, id) = NULL;
136
137   // Lookup method name [-(type)key]
138   {
139     Class      class = [instance class];
140     unsigned   clen  = [key cStringLength];
141     char       *cbuf;
142     const char *ckey;
143     SEL        sel;
144     struct objc_method* mth;
145     
146     cbuf = malloc(clen + 1);
147     [key getCString:cbuf]; cbuf[clen] = '\0';
148     ckey = cbuf;
149     sel = sel_get_any_uid(ckey);
150     
151     if (sel && (mth = class_get_instance_method(class, sel)) &&
152         method_get_number_of_arguments(mth) == 2) {
153       switch(*objc_skip_type_qualifiers(mth->method_types)) {
154         case _C_ID:
155           fptr = (id (*)(void*, void*, id))idMethodGetFunc;
156           break;
157         case _C_CHR:
158           fptr = (id (*)(void*, void*, id))charMethodGetFunc;
159           break;
160         case _C_UCHR:
161           fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc;
162           break;
163         case _C_SHT:
164           fptr = (id (*)(void*, void*, id))shortMethodGetFunc;
165           break;
166         case _C_USHT:
167           fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc;
168           break;
169         case _C_INT:
170           fptr = (id (*)(void*, void*, id))intMethodGetFunc;
171           break;
172         case _C_UINT:
173           fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc;
174           break;
175         case _C_LNG:
176           fptr = (id (*)(void*, void*, id))longMethodGetFunc;
177           break;
178         case _C_ULNG:
179           fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc;
180           break;
181         case 'q':
182           fptr = (id (*)(void*, void*, id))longLongMethodGetFunc;
183           break;
184         case 'Q':
185           fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc;
186           break;
187         case _C_FLT:
188           fptr = (id (*)(void*, void*, id))floatMethodGetFunc;
189           break;
190         case _C_DBL:
191           fptr = (id (*)(void*, void*, id))doubleMethodGetFunc;
192           break;
193       }
194       if (fptr) {
195         info1 = (void*)(mth->method_imp);
196         info2 = (void*)(mth->method_name);
197       }
198     }
199     if (cbuf) free(cbuf);
200   }
201         
202   // Lookup ivar name
203   if (!fptr) {
204     Class class = [instance class];
205     unsigned   clen;
206     char       *cbuf;
207     const char *ckey;
208     int i;
209     
210     clen = [key cStringLength];
211     cbuf = malloc(clen + 1);
212     [key getCString:cbuf]; cbuf[clen] = '\0';
213     ckey = cbuf;
214     
215     while (class) {
216       for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) {
217         if (!Strcmp(ckey, class->ivars->ivar_list[i].ivar_name)) {
218           switch(*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) {
219             case _C_ID:
220               fptr = (id (*)(void*, void*, id))idIvarGetFunc;
221               break;
222             case _C_CHR:
223               fptr = (id (*)(void*, void*, id))charIvarGetFunc;
224               break;
225             case _C_UCHR:
226               fptr = (id (*)(void*, void*, id))unsignedCharIvarGetFunc;
227               break;
228             case _C_SHT:
229               fptr = (id (*)(void*, void*, id))shortIvarGetFunc;
230               break;
231             case _C_USHT:
232               fptr = (id (*)(void*, void*, id))unsignedShortIvarGetFunc;
233               break;
234             case _C_INT:
235               fptr = (id (*)(void*, void*, id))intIvarGetFunc;
236               break;
237             case _C_UINT:
238               fptr = (id (*)(void*, void*, id))unsignedIntIvarGetFunc;
239               break;
240             case _C_LNG:
241               fptr = (id (*)(void*, void*, id))longIvarGetFunc;
242               break;
243             case _C_ULNG:
244               fptr = (id (*)(void*, void*, id))unsignedLongIvarGetFunc;
245               break;
246             case 'q':
247               fptr = (id (*)(void*, void*, id))longLongIvarGetFunc;
248               break;
249             case 'Q':
250               fptr = (id (*)(void*, void*, id))unsignedLongLongIvarGetFunc;
251               break;
252             case _C_FLT:
253               fptr = (id (*)(void*, void*, id))floatIvarGetFunc;
254               break;
255             case _C_DBL:
256               fptr = (id (*)(void*, void*, id))doubleIvarGetFunc;
257               break;
258           }
259           if (fptr) {
260             info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
261             break;
262           }
263         }
264       }
265       class = class->super_class;
266     }
267     if (cbuf) free(cbuf);
268   }
269     
270   // Make binding and insert into map
271   if (fptr) {
272     KeyValueMethod     *mkey;
273     GetKeyValueBinding *bin;
274         
275     mkey = Malloc(sizeof(KeyValueMethod));
276     bin  = Malloc(sizeof(GetKeyValueBinding));
277     mkey->key   = [key copy];
278     mkey->class = [instance class];
279     
280     bin->access = fptr;
281     bin->info1 = info1;
282     bin->info2 = info2;
283         
284     NSMapInsert(getValueBindings, mkey, bin);
285     ret = bin;
286   }
287     
288   // If no way to access value warn
289   if (!ret && keyValueDebug)
290     NSLog(@"cannnot get key `%@' for instance of class `%@'",
291           key, NSStringFromClass([instance class]));
292     
293   return ret;
294 }
295
296 static SetKeyValueBinding* newSetBinding(NSString* key, id instance)
297 {
298   SetKeyValueBinding *ret = NULL;
299   void *info1 = NULL;
300   void *info2 = NULL;
301   void (*fptr)(void*, void*, id, id) = NULL;
302     
303   // Lookup method name [-(void)setKey:(type)arg]
304   {
305     Class      class = [instance class];
306     unsigned   clen  = [key cStringLength];
307     char       *cbuf;
308     const char *ckey;
309     SEL        sel;
310     struct objc_method* mth;
311     char  sname[clen + 7];
312
313     cbuf = malloc(clen + 1);
314     [key getCString:cbuf]; cbuf[clen] = '\0';
315     ckey = cbuf;
316     
317     // Make sel from name
318     Strcpy(sname, "set");
319     Strcat(sname, ckey);
320     Strcat(sname, ":");
321     sname[3] = islower((int)sname[3]) ? toupper((int)sname[3]) : sname[3];
322     sel = sel_get_any_uid(sname);
323         
324     if (sel && (mth = class_get_instance_method(class, sel)) &&
325         method_get_number_of_arguments(mth) == 3 &&
326         *objc_skip_type_qualifiers(mth->method_types) == _C_VOID) {
327       char* argType = (char*)(mth->method_types);
328                 
329       argType = (char*)objc_skip_argspec(argType);    // skip return
330       argType = (char*)objc_skip_argspec(argType);    // skip self
331       argType = (char*)objc_skip_argspec(argType);    // skip SEL
332                 
333       switch(*objc_skip_type_qualifiers(argType)) {
334         case _C_ID:
335           fptr = (void (*)(void*, void*, id, id))idMethodSetFunc;
336           break;
337         case _C_CHR:
338           fptr = (void (*)(void*, void*, id, id))charMethodSetFunc;
339           break;
340         case _C_UCHR:
341           fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc;
342           break;
343         case _C_SHT:
344           fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc;
345           break;
346         case _C_USHT:
347           fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc;
348           break;
349         case _C_INT:
350           fptr = (void (*)(void*, void*, id, id))intMethodSetFunc;
351           break;
352         case _C_UINT:
353           fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc;
354           break;
355         case _C_LNG:
356           fptr = (void (*)(void*, void*, id, id))longMethodSetFunc;
357           break;
358         case _C_ULNG:
359           fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc;
360           break;
361         case 'q':
362           fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc;
363           break;
364         case 'Q':
365           fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc;
366           break;
367         case _C_FLT:
368           fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc;
369           break;
370         case _C_DBL:
371           fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc;
372           break;
373       }
374       if (fptr) {
375         info1 = (void*)(mth->method_imp);
376         info2 = (void*)(mth->method_name);
377       }
378     }
379     if (cbuf) free(cbuf);
380   }    
381   // Lookup ivar name
382   if (!fptr) {
383     Class class = [instance class];
384     unsigned   clen  = [key cStringLength];
385     char       *cbuf;
386     const char *ckey;
387     int i;
388
389     cbuf = malloc(clen + 1);
390     [key getCString:cbuf]; cbuf[clen] = '\0';
391     ckey = cbuf;
392         
393     while (class) {
394       for (i = 0; class->ivars && i < class->ivars->ivar_count; i++) {
395         if (!Strcmp(ckey, class->ivars->ivar_list[i].ivar_name)) {
396           switch(*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type)) {
397             case _C_ID:
398               fptr = (void (*)(void*, void*, id, id))idIvarSetFunc;
399               break;
400             case _C_CHR:
401               fptr = (void (*)(void*, void*, id, id))charIvarSetFunc;
402               break;
403             case _C_UCHR:
404               fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc;
405               break;
406             case _C_SHT:
407               fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc;
408               break;
409             case _C_USHT:
410               fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc;
411               break;
412             case _C_INT:
413               fptr = (void (*)(void*, void*, id, id))intIvarSetFunc;
414               break;
415             case _C_UINT:
416               fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc;
417               break;
418             case _C_LNG:
419               fptr = (void (*)(void*, void*, id, id))longIvarSetFunc;
420               break;
421             case _C_ULNG:
422               fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc;
423               break;
424             case 'q':
425               fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc;
426               break;
427             case 'Q':
428               fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc;
429               break;
430             case _C_FLT:
431               fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc;
432               break;
433             case _C_DBL:
434               fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc;
435               break;
436           }
437           if (fptr) {
438             info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
439             break;
440           }
441         }
442       }
443       class = class->super_class;
444     }
445     if (cbuf) free(cbuf);
446   }
447     
448   // Make binding and insert into map
449   if (fptr) {
450     KeyValueMethod     *mkey;
451     SetKeyValueBinding *bin;
452         
453     mkey = Malloc(sizeof(KeyValueMethod));
454     bin  = Malloc(sizeof(SetKeyValueBinding));
455     mkey->key = [key copy];
456     mkey->class = [instance class];
457     
458     bin->access = fptr;
459     bin->info1 = info1;
460     bin->info2 = info2;
461         
462     NSMapInsert(setValueBindings, mkey, bin);
463     ret = bin;
464   }
465   // If no way to access value warn
466   if (!ret && keyValueDebug)
467     NSLog(@"cannnot set key `%@' for instance of class `%@'",
468           key, NSStringFromClass([instance class]));
469   
470   return ret;
471 }
472
473 /*
474  * MapTable initialization
475  */
476
477 static unsigned keyValueMapHash(NSMapTable* table, KeyValueMethod* map) {
478   return [map->key hash] + (((int)(map->class)) >> 4);
479 }
480
481 static BOOL keyValueMapCompare(NSMapTable* table,
482                                KeyValueMethod* map1, KeyValueMethod* map2)
483 {
484   return (map1->class == map2->class) && [map1->key isEqual:map2->key];
485 }
486
487 static void mapRetainNothing(NSMapTable* table, KeyValueMethod* map) {
488 }
489
490 static void keyValueMapKeyRelease(NSMapTable* table, KeyValueMethod* map) {
491   [map->key release];
492   Free(map);
493 }
494
495 static void keyValueMapValRelease(NSMapTable* table, void* map) {
496   Free(map);
497 }
498
499 static NSString* keyValueMapDescribe(NSMapTable* table, KeyValueMethod* map) {
500   if (StringClass == Nil) StringClass = [NSString class];
501   return [StringClass stringWithFormat:@"%@:%@",
502                    NSStringFromClass(map->class), map->key];
503 }
504
505 static NSString* describeBinding(NSMapTable* table, GetKeyValueBinding* bin) {
506   if (StringClass == Nil) StringClass = [NSString class];
507   return [StringClass stringWithFormat:@"%08x:%08x", bin->info1, bin->info2];
508 }
509
510 static NSMapTableKeyCallBacks keyValueKeyCallbacks = {
511   (unsigned(*)(NSMapTable *, const void *))keyValueMapHash,
512   (BOOL(*)(NSMapTable *, const void *, const void *))keyValueMapCompare,
513   (void (*)(NSMapTable *, const void *anObject))mapRetainNothing,
514   (void (*)(NSMapTable *, void *anObject))keyValueMapKeyRelease,
515   (NSString *(*)(NSMapTable *, const void *))keyValueMapDescribe,
516   (const void *)NULL
517 }; 
518
519 const NSMapTableValueCallBacks keyValueValueCallbacks = {
520   (void (*)(NSMapTable *, const void *))mapRetainNothing,
521   (void (*)(NSMapTable *, void *))keyValueMapValRelease,
522   (NSString *(*)(NSMapTable *, const void *))describeBinding
523 }; 
524
525 static void initKeyValueBindings(void)
526 {
527   getValueBindings = NSCreateMapTable(keyValueKeyCallbacks, 
528                                       keyValueValueCallbacks, 31);
529   setValueBindings = NSCreateMapTable(keyValueKeyCallbacks, 
530                                       keyValueValueCallbacks, 31);
531   keyValueInit = YES;
532 }
533
534 /* 
535  * Access Methods 
536  */
537
538 static inline void removeAllBindings(void) {
539   NSResetMapTable(getValueBindings);
540   NSResetMapTable(setValueBindings);
541 }
542
543 static inline id getValue(NSString* key, id instance) {
544   KeyValueMethod     mkey = { key, [instance class] };
545   GetKeyValueBinding *bin;
546   id value = nil;
547   
548   if (NumberClass == Nil)
549     NumberClass = [NSNumber class];
550   
551   // Check Init
552   if (!keyValueInit)
553     initKeyValueBindings();
554     
555   // Get existing binding
556   bin = (GetKeyValueBinding *)NSMapGet(getValueBindings, &mkey);
557     
558   // Create new binding
559   if (bin == NULL)
560     bin = newGetBinding(key, instance);
561     
562   // Get value if binding is ok
563   if (bin)
564     value = bin->access(bin->info1, bin->info2, instance);
565     
566   return value;
567 }
568
569 static inline BOOL setValue(NSString* key, id instance, id value)
570 {
571   KeyValueMethod mkey = {key, [instance class]};
572   SetKeyValueBinding* bin;
573
574   if (NumberClass == Nil)
575     NumberClass = [NSNumber class];
576     
577   // Check Init
578   if (!keyValueInit)
579     initKeyValueBindings();
580     
581   // Get existing binding
582   bin = (SetKeyValueBinding *)NSMapGet(setValueBindings, &mkey);
583     
584   // Create new binding
585   if (bin == NULL)
586     bin = newSetBinding(key, instance);
587     
588   // Get value if binding is ok
589   if (bin)
590     bin->access(bin->info1, bin->info2, instance, value);
591     
592   return (bin != NULL);
593 }
594
595 + (BOOL)accessInstanceVariablesDirectly {
596   return NO;
597 }
598
599 - (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
600   NSDictionary *ui;
601
602   ui = [NSDictionary dictionaryWithObjectsAndKeys:
603                        self, @"EOTargetObjectUserInfoKey",
604                        [self class],
605                        @"EOTargetObjectClassUserInfoKey",
606                        _key, @"EOUnknownUserInfoKey",
607                      nil];
608   [[NSException exceptionWithName:@"EOUnknownKeyException"
609                 reason:@"called -takeValue:forKey: with unknown key"
610                 userInfo:ui] raise];
611 }
612
613 - (id)handleQueryWithUnboundKey:(NSString *)_key {
614   NSDictionary *ui;
615
616   ui = [NSDictionary dictionaryWithObjectsAndKeys:
617                        self, @"EOTargetObjectUserInfoKey",
618                        _key, @"EOUnknownUserInfoKey",
619                      nil];
620   [[NSException exceptionWithName:@"EOUnknownKeyException"
621                 reason:@"called -valueForKey: with unknown key"
622                 userInfo:ui] raise];
623   return nil;
624 }
625
626 - (void)unableToSetNullForKey:(NSString *)_key {
627   [NSException raise:@"NSInvalidArgumentException" 
628                format:
629                   @"EOKeyValueCoding cannot set EONull value for key %@,"
630                   @"in instance of %@ class.",
631                   _key, NSStringFromClass([self class])];
632 }
633
634 + (void)flushAllKeyBindings {
635   removeAllBindings();
636 }
637 - (void)flushKeyBindings {
638   // EOF 1.1 method
639   removeAllBindings();
640 }
641
642 - (void)setKeyValueCodingWarnings:(BOOL)aFlag {
643   keyValueDebug = aFlag;
644 }
645
646 - (void)takeValuesFromDictionary:(NSDictionary *)dictionary {
647   NSEnumerator *keyEnum;
648   id key;
649
650   if (null == nil) null = [EONull null];
651   keyEnum = [dictionary keyEnumerator];
652     
653   while ((key = [keyEnum nextObject])) {
654     id value;
655     
656     value = [dictionary objectForKey:key];
657
658     /* automagically convert EONull to nil */
659     if (value == null) value = nil;
660     
661     [self takeValue:value forKey:key];
662     
663 #if 0 // this doesn't support overridden methods ...
664     if (!setValue(key, self, value)) {
665       [self handleTakeValue:value forUnboundKey:key];
666     }
667 #endif
668   }
669 }
670
671 - (NSDictionary *)valuesForKeys:(NSArray *)keys {
672   static Class  NSDictionaryClass = Nil;
673   int n = [keys count];
674
675   if (NSDictionaryClass == Nil)
676     NSDictionaryClass = [NSDictionary class];
677   if (null == nil)
678     null = [EONull null];
679   
680   if (n == 0)
681     return [NSDictionaryClass dictionary];
682   else if (n == 1) {
683     NSString *key;
684     id value;
685     
686     key   = [keys objectAtIndex:0];
687     //value = getValue(key, self);
688     value = [self valueForKey:key];
689
690     /* automagically convert 'nil' to EONull */
691     if (value == nil) value = null;
692     
693     return [NSDictionaryClass dictionaryWithObject:value forKey:key];
694   }
695   else {
696     id newKeys[n];
697     id newVals[n];
698     int i;
699         
700     for (i = 0; i < n; i++) {
701       id key;
702       id val;
703       
704       key = [keys objectAtIndex:i];
705       //val = getValue(key, self);
706       val = [self valueForKey:key];
707
708       /* automagically convert 'nil' to EONull */
709       if (val == nil) val = null;
710       
711       newKeys[i] = key;
712       newVals[i] = val;
713     }
714     
715     return [NSDictionaryClass dictionaryWithObjects:newVals
716                               forKeys:newKeys
717                               count:n];
718   }
719 }
720
721 - (void)takeValue:(id)_value forKey:(NSString *)_key {
722   if (!setValue(_key, self, _value)) {
723     //NSLog(@"ERROR(%s): couldn't take value for key %@", key);
724     [self handleTakeValue:_value forUnboundKey:_key];
725   }
726 }
727
728 - (id)valueForKey:(NSString *)key {
729   id val;
730   
731   if ((val = getValue(key, self)))
732     return val;
733   
734   return nil;
735 }
736
737 /* stored values */
738
739 + (BOOL)useStoredAccessor {
740   return YES;
741 }
742
743 - (void)takeStoredValue:(id)_value forKey:(NSString *)_key {
744   if ([[self class] useStoredAccessor]) {
745     BOOL ok = YES;
746
747     /* this should be different */
748     
749     ok = setValue(_key, self, _value);
750     if (!ok) [self handleTakeValue:_value forUnboundKey:_key];
751   }
752   else
753     [self takeValue:_value forKey:_key];
754 }
755
756 - (id)storedValueForKey:(NSString *)_key {
757   if ([[self class] useStoredAccessor]) {
758     id val;
759
760     /* this should be different */
761     
762     if ((val = getValue(_key, self)))
763       return val;
764
765     /* val = [self handleQueryWithUnboundKey:_key] */
766     
767     return nil;
768   }
769   else
770     return [self valueForKey:_key];
771 }
772
773 @end /* NSObject(EOKeyValueCoding) */
774
775 @implementation NSObject(EOKeyPathValueCoding)
776
777 - (void)takeValue:(id)_value forKeyPath:(NSString *)_keyPath {
778   NSArray *keyPath;
779   unsigned i, count;
780   id target;
781
782   keyPath = [_keyPath componentsSeparatedByString:@"."];
783   count = [keyPath count];
784
785   if (count < 2)
786     [self takeValue:_value forKey:_keyPath];
787   else {
788
789     target = self;
790     for (i = 0; i < (count - 1) ; i++) {
791       if ((target = [target valueForKey:[keyPath objectAtIndex:i]]) == nil)
792         /* nil component */
793         return;
794     }
795   
796     [target takeValue:_value forKey:[keyPath lastObject]];
797   }
798 }
799 - (id)valueForKeyPath:(NSString *)_keyPath {
800 #if 1
801   const unsigned char *buf;
802   unsigned int  i, start, len;
803   id value;
804
805   if ((len = [_keyPath cStringLength]) == 0)
806     return [self valueForKey:_keyPath];
807   
808   if (StringClass == Nil) StringClass = [NSString class];
809   value = self;
810   
811   buf = [_keyPath cString];
812   if (index(buf, '.') == NULL)
813     /* no point contained .. */
814     return [self valueForKey:_keyPath];
815   
816   for (i = start = 0; i < len; i++) {
817     if (buf[i] == '.') {
818       /* found a pt */
819       NSString *key;
820       
821       key = (start < i)
822         ? [StringClass stringWithCString:&(buf[start]) length:(i - start)]
823         : @"";
824       
825       if ((value = [value valueForKey:key]) == nil)
826         return nil;
827       
828       start = (i + 1); /* next part is after the pt */
829     }
830   }
831   /* check last part */
832   {
833     NSString *key;
834     
835     key = (start < i)
836       ? [StringClass stringWithCString:&(buf[start]) length:(i - start)]
837       : @"";
838     return [value valueForKey:key];
839   }
840 #else
841   /* naive implementation */
842   NSEnumerator *keyPath;
843   NSString *key;
844   id value;
845   
846   value   = self;
847   keyPath = [[_keyPath componentsSeparatedByString:@"."] objectEnumerator];
848   while ((key = [keyPath nextObject]) && (value != nil))
849     value = [value valueForKey:key];
850   return value;
851 #endif
852 }
853
854 @end /* NSObject(EOKeyPathValueCoding) */
855
856 @implementation NSArray(EOKeyValueCoding)
857
858 - (id)computeSumForKey:(NSString *)_key {
859   unsigned i, cc = [self count];
860   id (*objAtIdx)(id, SEL, unsigned int);
861   double sum;
862
863   if (cc == 0) return [NSNumber numberWithDouble:0.0];
864   
865   objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
866     
867   for (i = 0, sum = 0.0; i < cc; i++) {
868     register id o;
869       
870     o = objAtIdx(self, @selector(objectAtIndex:), i);
871     sum += [o doubleValue];
872   }
873   return [NSNumber numberWithDouble:sum];
874 }
875
876 - (id)computeAvgForKey:(NSString *)_key {
877   unsigned i, cc = [self count];
878   id (*objAtIdx)(id, SEL, unsigned int);
879   double sum;
880
881   if (cc == 0) return [NSNumber numberWithDouble:0.0];
882   
883   objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
884     
885   for (i = 0, sum = 0.0; i < cc; i++) {
886     register id o;
887       
888     o = objAtIdx(self, @selector(objectAtIndex:), i);
889
890     sum += [o doubleValue];
891   }
892   return [NSNumber numberWithDouble:(sum / (double)cc)];
893 }
894
895 - (id)computeCountForKey:(NSString *)_key {
896   return [NSNumber numberWithUnsignedInt:[self count]];
897 }
898
899 - (id)computeMaxForKey:(NSString *)_key {
900   unsigned i, cc = [self count];
901   id (*objAtIdx)(id, SEL, unsigned int);
902   double max;
903
904   if (cc == 0) return nil;
905     
906   objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
907
908   max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
909   for (i = 1; i < cc; i++) {
910     register double ov;
911       
912     ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
913     if (ov > max) max = ov;
914   }
915   return [NSNumber numberWithDouble:max];
916 }
917
918 - (id)computeMinForKey:(NSString *)_key {
919   unsigned i, cc = [self count];
920   id (*objAtIdx)(id, SEL, unsigned int);
921   double min;
922
923   if (cc == 0) return nil;
924   
925   objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
926     
927   min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
928   for (i = 1; i < cc; i++) {
929     register double ov;
930       
931     ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
932     if (ov < min) min = ov;
933   }
934   return [NSNumber numberWithDouble:min];
935 }
936
937 - (id)valueForKey:(NSString *)_key {
938   if ([_key hasPrefix:@"@"]) {
939     /* process a computed function */
940     const char *keyStr;
941     char       *bufPtr;
942     unsigned   keyLen = [_key cStringLength];
943     char       *kbuf, *buf;
944     SEL        sel;
945
946     kbuf = malloc(keyLen + 4);
947     buf  = malloc(keyLen + 20);
948     [_key getCString:kbuf];
949     keyStr = kbuf;
950     bufPtr = buf;
951     strcpy(buf, "compute");       bufPtr += 7;
952     *bufPtr = toupper(keyStr[1]); bufPtr++;
953     strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
954     strcpy(bufPtr, "ForKey:");
955     if (kbuf) free(kbuf);
956     
957     sel = sel_get_any_uid(buf);
958     if (buf) free(buf);
959     
960     return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
961   }
962   else {
963     /* process the _key in a map function */
964     unsigned i, cc = [self count];
965     id objects[cc];
966     id (*objAtIdx)(id, SEL, unsigned int);
967
968 #if DEBUG
969     if ([_key isEqualToString:@"count"]) {
970       NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
971             @"PROBABLY WANT TO USE @count INSTEAD !",
972             __PRETTY_FUNCTION__);
973       return [self valueForKey:@"@count"];
974     }
975 #endif
976     
977     objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
978     
979     for (i = 0; i < cc; i++) {
980       register id o;
981       
982       o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
983       
984       if (o)
985         objects[i] = o;
986       else {
987         if (null == nil) null = [EONull null];
988         objects[i] = null;
989       }
990     }
991     
992     return [NSArray arrayWithObjects:objects count:cc];
993   }
994 }
995
996 @end /* NSArray(EOKeyValueCoding) */
997
998 @implementation NSDictionary(EOKeyValueCoding)
999
1000 - (NSDictionary *)valuesForKeys:(NSArray *)keys {
1001   int n = [keys count];
1002
1003   if (n == 0)
1004     return [NSDictionary dictionary];
1005   else if (n == 1) {
1006     NSString *key = [keys objectAtIndex:0];
1007
1008     return [NSDictionary dictionaryWithObject:[self objectForKey:key]
1009                          forKey:key];
1010   }
1011   else {
1012     NSMutableArray *newKeys, *newVals;
1013     int i;
1014         
1015     newKeys = [NSMutableArray arrayWithCapacity:n];
1016     newVals = [NSMutableArray arrayWithCapacity:n];
1017     
1018     for (i = 0; i < n; i++) {
1019       id key = [keys objectAtIndex:i];
1020       id val = [self objectForKey:key];
1021       
1022       if (val) {
1023         [newKeys addObject:key];
1024         [newVals addObject:val];
1025       }
1026     }
1027     
1028     return [NSDictionary dictionaryWithObjects:newVals forKeys:newKeys];
1029   }
1030 }
1031
1032 - (void)takeValue:(id)_value forKey:(NSString *)_key {
1033   //#warning takeValue:forKey: is ignored in NSDictionaries !
1034   // ignore
1035   //[self handleTakeValue:_value forUnboundKey:_key];
1036 }
1037
1038 - (id)valueForKey:(id)_key {
1039   id obj;
1040   
1041   if (_key == nil) // TODO: warn about nil key?
1042     return nil;
1043   if ((obj = [self objectForKey:_key]) == nil)
1044     return nil;
1045   
1046   if (null == nil) null = [[NSNull null] retain];
1047   if (obj == null)
1048     return nil;
1049     
1050   return obj;
1051 }
1052
1053 @end /* NSDictionary(EOKeyValueCoding) */
1054
1055 @implementation NSMutableDictionary(EOKeyValueCoding)
1056
1057 - (void)takeValuesFromDictionary:(NSDictionary*)dictionary {
1058   [self addEntriesFromDictionary:dictionary];
1059 }
1060
1061 - (void)takeValue:(id)_value forKey:(id)_key {
1062   if (_value == nil) _value = [NSNull null];
1063   [self setObject:_value forKey:_key];
1064 }
1065
1066 @end /* NSMutableDictionary(EOKeyValueCoding) */
1067
1068 /*
1069  *  Accessor functions
1070  */
1071
1072 /* ACCESS to keys of id type. */
1073
1074 static id idMethodGetFunc(void* info1, void* info2, id self) {
1075   id (*fptr)(id, SEL) = (id(*)(id, SEL))info1;
1076   id val = fptr(self, (SEL)info2);
1077   return val;
1078 }
1079 static id idIvarGetFunc(void* info1, void* info2, id self) {
1080   id* ptr = (id*)((char*)self + (int)info2);
1081   return *ptr;
1082 }
1083
1084 static void idMethodSetFunc(void* info1, void* info2, id self, id val) {
1085   void (*fptr)(id, SEL, id) = (void(*)(id, SEL, id))info1;
1086   fptr(self, (SEL)info2, val);
1087 }
1088
1089 static void idIvarSetFunc(void* info1, void* info2, id self, id val)
1090 {
1091   id* ptr = (id*)((char*)self + (int)info2);
1092   ASSIGN(*ptr, val);
1093 }
1094
1095 /* ACCESS to keys of char type. */
1096
1097 static id charMethodGetFunc(void* info1, void* info2, id self)
1098 {
1099   char (*fptr)(id, SEL) = (char(*)(id, SEL))info1;
1100   char val = fptr(self, (SEL)info2);
1101   return [NumberClass numberWithChar:val];
1102 }
1103
1104 static id charIvarGetFunc(void* info1, void* info2, id self)
1105 {
1106   char* ptr = (char*)((char*)self + (int)info2);
1107   return [NumberClass numberWithChar:*ptr];
1108 }
1109
1110 static void charMethodSetFunc(void* info1, void* info2, id self, id val)
1111 {
1112   void (*fptr)(id, SEL, char) = (void(*)(id, SEL, char))info1;
1113   fptr(self, (SEL)info2, [val charValue]);
1114 }
1115
1116 static void charIvarSetFunc(void* info1, void* info2, id self, id val)
1117 {
1118   char* ptr = (char*)((char*)self + (int)info2);
1119   *ptr = [val charValue];
1120 }
1121
1122
1123 /* ACCESS to keys of unsigned char type. */
1124
1125 static id unsignedCharMethodGetFunc(void* info1, void* info2, id self)
1126 {
1127   unsigned char (*fptr)(id, SEL) = (unsigned char(*)(id, SEL))info1;
1128   unsigned char val = fptr(self, (SEL)info2);
1129   return [NumberClass numberWithUnsignedChar:val];
1130 }
1131
1132 static id unsignedCharIvarGetFunc(void* info1, void* info2, id self)
1133 {
1134   unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
1135   return [NumberClass numberWithUnsignedChar:*ptr];
1136 }
1137
1138 static void unsignedCharMethodSetFunc(void* info1, void* info2, id self, id val)
1139 {
1140   void (*fptr)(id, SEL, unsigned char) = (void(*)(id, SEL, unsigned char))info1;
1141   fptr(self, (SEL)info2, [val unsignedCharValue]);
1142 }
1143
1144 static void unsignedCharIvarSetFunc(void* info1, void* info2, id self, id val)
1145 {
1146   unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
1147   *ptr = [val unsignedCharValue];
1148 }
1149
1150
1151 /* ACCESS to keys of short type. */
1152
1153 static id shortMethodGetFunc(void* info1, void* info2, id self)
1154 {
1155   short (*fptr)(id, SEL) = (short(*)(id, SEL))info1;
1156   short val = fptr(self, (SEL)info2);
1157   return [NumberClass numberWithShort:val];
1158 }
1159
1160 static id shortIvarGetFunc(void* info1, void* info2, id self)
1161 {
1162   short* ptr = (short*)((char*)self + (int)info2);
1163   return [NumberClass numberWithShort:*ptr];
1164 }
1165
1166 static void shortMethodSetFunc(void* info1, void* info2, id self, id val)
1167 {
1168   void (*fptr)(id, SEL, short) = (void(*)(id, SEL, short))info1;
1169   fptr(self, (SEL)info2, [val shortValue]);
1170 }
1171
1172 static void shortIvarSetFunc(void* info1, void* info2, id self, id val)
1173 {
1174   short* ptr = (short*)((char*)self + (int)info2);
1175   *ptr = [val shortValue];
1176 }
1177
1178
1179 /* ACCESS to keys of unsigned short type. */
1180
1181 static id unsignedShortMethodGetFunc(void* info1, void* info2, id self)
1182 {
1183   unsigned short (*fptr)(id, SEL) = (unsigned short(*)(id, SEL))info1;
1184   unsigned short val = fptr(self, (SEL)info2);
1185   return [NumberClass numberWithUnsignedShort:val];
1186 }
1187
1188 static id unsignedShortIvarGetFunc(void* info1, void* info2, id self)
1189 {
1190   unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
1191   return [NumberClass numberWithUnsignedShort:*ptr];
1192 }
1193
1194 static void unsignedShortMethodSetFunc(void* info1, void* info2, id self, id val)
1195 {
1196   void (*fptr)(id, SEL, unsigned short) = (void(*)(id, SEL, unsigned short))info1;
1197   fptr(self, (SEL)info2, [val unsignedShortValue]);
1198 }
1199
1200 static void unsignedShortIvarSetFunc(void* info1, void* info2, id self, id val)
1201 {
1202   unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
1203   *ptr = [val unsignedShortValue];
1204 }
1205
1206
1207 /* ACCESS to keys of int type. */
1208
1209 static id intMethodGetFunc(void* info1, void* info2, id self)
1210 {
1211   int (*fptr)(id, SEL) = (int(*)(id, SEL))info1;
1212   int val = fptr(self, (SEL)info2);
1213   return [NumberClass numberWithInt:val];
1214 }
1215
1216 static id intIvarGetFunc(void* info1, void* info2, id self)
1217 {
1218   int* ptr = (int*)((char*)self + (int)info2);
1219   return [NumberClass numberWithInt:*ptr];
1220 }
1221
1222 static void intMethodSetFunc(void* info1, void* info2, id self, id val)
1223 {
1224   void (*fptr)(id, SEL, int) = (void(*)(id, SEL, int))info1;
1225   fptr(self, (SEL)info2, [val intValue]);
1226 }
1227
1228 static void intIvarSetFunc(void* info1, void* info2, id self, id val)
1229 {
1230   int* ptr = (int*)((char*)self + (int)info2);
1231   *ptr = [val intValue];
1232 }
1233
1234
1235 /* ACCESS to keys of unsigned int type. */
1236
1237 static id unsignedIntMethodGetFunc(void* info1, void* info2, id self)
1238 {
1239   unsigned int (*fptr)(id, SEL) = (unsigned int(*)(id, SEL))info1;
1240   unsigned int val = fptr(self, (SEL)info2);
1241   return [NumberClass numberWithUnsignedInt:val];
1242 }
1243
1244 static id unsignedIntIvarGetFunc(void* info1, void* info2, id self)
1245 {
1246   unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
1247   return [NumberClass numberWithUnsignedInt:*ptr];
1248 }
1249
1250 static void unsignedIntMethodSetFunc(void* info1, void* info2, id self, id val)
1251 {
1252   void (*fptr)(id, SEL, unsigned int) = (void(*)(id, SEL, unsigned int))info1;
1253   fptr(self, (SEL)info2, [val unsignedIntValue]);
1254 }
1255
1256 static void unsignedIntIvarSetFunc(void* info1, void* info2, id self, id val)
1257 {
1258   unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
1259   *ptr = [val unsignedIntValue];
1260 }
1261
1262
1263 /* ACCESS to keys of long type. */
1264
1265 static id longMethodGetFunc(void* info1, void* info2, id self)
1266 {
1267   long (*fptr)(id, SEL) = (long(*)(id, SEL))info1;
1268   long val = fptr(self, (SEL)info2);
1269   return [NumberClass numberWithLong:val];
1270 }
1271
1272 static id longIvarGetFunc(void* info1, void* info2, id self)
1273 {
1274   long* ptr = (long*)((char*)self + (int)info2);
1275   return [NumberClass numberWithLong:*ptr];
1276 }
1277
1278 static void longMethodSetFunc(void* info1, void* info2, id self, id val)
1279 {
1280   void (*fptr)(id, SEL, long) = (void(*)(id, SEL, long))info1;
1281   fptr(self, (SEL)info2, [val longValue]);
1282 }
1283
1284 static void longIvarSetFunc(void* info1, void* info2, id self, id val)
1285 {
1286   long* ptr = (long*)((char*)self + (int)info2);
1287   *ptr = [val longValue];
1288 }
1289
1290
1291 /* unsigned long type */
1292
1293 static id unsignedLongMethodGetFunc(void* info1, void* info2, id self) {
1294   unsigned long (*fptr)(id, SEL) = (unsigned long(*)(id, SEL))info1;
1295   unsigned long val = fptr(self, (SEL)info2);
1296   return [NumberClass numberWithUnsignedLong:val];
1297 }
1298
1299 static id unsignedLongIvarGetFunc(void* info1, void* info2, id self) {
1300   unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
1301   return [NumberClass numberWithUnsignedLong:*ptr];
1302 }
1303
1304 static void unsignedLongMethodSetFunc(void* info1, void* info2, id self, id val) {
1305   void (*fptr)(id, SEL, unsigned long) = (void(*)(id, SEL, unsigned long))info1;
1306   fptr(self, (SEL)info2, [val unsignedLongValue]);
1307 }
1308
1309 static void unsignedLongIvarSetFunc(void* info1, void* info2, id self, id val) {
1310   unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
1311   *ptr = [val unsignedLongValue];
1312 }
1313
1314
1315 /* long long type */
1316
1317 static id longLongMethodGetFunc(void* info1, void* info2, id self) {
1318   long long (*fptr)(id, SEL) = (long long(*)(id, SEL))info1;
1319   long long val = fptr(self, (SEL)info2);
1320   return [NumberClass numberWithLongLong:val];
1321 }
1322
1323 static id longLongIvarGetFunc(void* info1, void* info2, id self) {
1324   long long* ptr = (long long*)((char*)self + (int)info2);
1325   return [NumberClass numberWithLongLong:*ptr];
1326 }
1327
1328 static void longLongMethodSetFunc(void* info1, void* info2, id self, id val) {
1329   void (*fptr)(id, SEL, long long) = (void(*)(id, SEL, long long))info1;
1330   fptr(self, (SEL)info2, [val longLongValue]);
1331 }
1332
1333 static void longLongIvarSetFunc(void* info1, void* info2, id self, id val) {
1334   long long* ptr = (long long*)((char*)self + (int)info2);
1335   *ptr = [val longLongValue];
1336 }
1337
1338
1339 /* unsigned long long type */
1340
1341 static id unsignedLongLongMethodGetFunc(void* info1, void* info2, id self) {
1342   unsigned long long (*fptr)(id, SEL) = (unsigned long long(*)(id, SEL))info1;
1343   unsigned long long val = fptr(self, (SEL)info2);
1344   return [NumberClass numberWithUnsignedLongLong:val];
1345 }
1346
1347 static id unsignedLongLongIvarGetFunc(void* info1, void* info2, id self) {
1348   unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
1349   return [NumberClass numberWithUnsignedLongLong:*ptr];
1350 }
1351
1352 static void unsignedLongLongMethodSetFunc(void* info1, void* info2, id self, id val) {
1353   void (*fptr)(id, SEL, unsigned long long) = (void(*)(id, SEL, unsigned long long))info1;
1354   fptr(self, (SEL)info2, [val unsignedLongLongValue]);
1355 }
1356
1357 static void unsignedLongLongIvarSetFunc(void* info1, void* info2, id self, id val) {
1358   unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
1359   *ptr = [val unsignedLongLongValue];
1360 }
1361
1362
1363 /* float */
1364
1365 static id floatMethodGetFunc(void* info1, void* info2, id self) {
1366   float (*fptr)(id, SEL) = (float(*)(id, SEL))info1;
1367   float val = fptr(self, (SEL)info2);
1368   return [NumberClass numberWithFloat:val];
1369 }
1370
1371 static id floatIvarGetFunc(void* info1, void* info2, id self) {
1372   float* ptr = (float*)((char*)self + (int)info2);
1373   return [NumberClass numberWithFloat:*ptr];
1374 }
1375
1376 static void floatMethodSetFunc(void* info1, void* info2, id self, id val) {
1377   void (*fptr)(id, SEL, float) = (void(*)(id, SEL, float))info1;
1378   fptr(self, (SEL)info2, [val floatValue]);
1379 }
1380
1381 static void floatIvarSetFunc(void* info1, void* info2, id self, id val) {
1382   float* ptr = (float*)((char*)self + (int)info2);
1383   *ptr = [val floatValue];
1384 }
1385
1386
1387 /* double */
1388
1389 static id doubleMethodGetFunc(void* info1, void* info2, id self) {
1390   double (*fptr)(id, SEL) = (double(*)(id, SEL))info1;
1391   double val = fptr(self, (SEL)info2);
1392   return [NumberClass numberWithDouble:val];
1393 }
1394
1395 static id doubleIvarGetFunc(void* info1, void* info2, id self) {
1396   double* ptr = (double*)((char*)self + (int)info2);
1397   return [NumberClass numberWithDouble:*ptr];
1398 }
1399
1400 static void doubleMethodSetFunc(void* info1, void* info2, id self, id val) {
1401   void (*fptr)(id, SEL, double) = (void(*)(id, SEL, double))info1;
1402   fptr(self, (SEL)info2, [val doubleValue]);
1403 }
1404
1405 static void doubleIvarSetFunc(void* info1, void* info2, id self, id val) {
1406   double* ptr = (double*)((char*)self + (int)info2);
1407   *ptr = [val doubleValue];
1408 }
1409
1410 #else /* NeXT_Foundation_LIBRARY */
1411
1412 @implementation NSArray(EOKeyValueCoding)
1413
1414 - (id)computeSumForKey:(NSString *)_key {
1415   unsigned i, cc = [self count];
1416   id (*objAtIdx)(id, SEL, unsigned int);
1417   double sum;
1418
1419   if (cc == 0) return [NSNumber numberWithDouble:0.0];
1420   
1421   objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
1422     
1423   for (i = 0, sum = 0.0; i < cc; i++) {
1424     register id o;
1425       
1426     o = objAtIdx(self, @selector(objectAtIndex:), i);
1427     sum += [o doubleValue];
1428   }
1429   return [NSNumber numberWithDouble:sum];
1430 }
1431
1432 - (id)computeAvgForKey:(NSString *)_key {
1433   unsigned i, cc = [self count];
1434   id (*objAtIdx)(id, SEL, unsigned int);
1435   double sum;
1436
1437   if (cc == 0) return [NSNumber numberWithDouble:0.0];
1438   
1439   objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1440     
1441   for (i = 0, sum = 0.0; i < cc; i++) {
1442     register id o;
1443       
1444     o = objAtIdx(self, @selector(objectAtIndex:), i);
1445
1446     sum += [o doubleValue];
1447   }
1448   return [NSNumber numberWithDouble:(sum / (double)cc)];
1449 }
1450
1451 - (id)computeCountForKey:(NSString *)_key {
1452   return [NSNumber numberWithUnsignedInt:[self count]];
1453 }
1454
1455 - (id)computeMaxForKey:(NSString *)_key {
1456   unsigned i, cc = [self count];
1457   id (*objAtIdx)(id, SEL, unsigned int);
1458   double max;
1459
1460   if (cc == 0) return nil;
1461     
1462   objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1463
1464   max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
1465   for (i = 1; i < cc; i++) {
1466     register double ov;
1467       
1468     ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
1469     if (ov > max) max = ov;
1470   }
1471   return [NSNumber numberWithDouble:max];
1472 }
1473
1474 - (id)computeMinForKey:(NSString *)_key {
1475   unsigned i, cc = [self count];
1476   id (*objAtIdx)(id, SEL, unsigned int);
1477   double min;
1478
1479   if (cc == 0) return nil;
1480   
1481   objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1482     
1483   min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
1484   for (i = 1; i < cc; i++) {
1485     register double ov;
1486       
1487     ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
1488     if (ov < min) min = ov;
1489   }
1490   return [NSNumber numberWithDouble:min];
1491 }
1492
1493 - (id)valueForKey:(NSString *)_key {
1494   if (null == nil) null = [[EONull null] retain];
1495   
1496   if ([_key hasPrefix:@"@"]) {
1497     /* process a computed function */
1498     const char *keyStr;
1499     char       *bufPtr;
1500     unsigned   keyLen = [_key cStringLength];
1501     char       *kbuf, *buf;
1502     SEL        sel;
1503
1504     kbuf = malloc(keyLen + 1);
1505     buf  = malloc(keyLen + 16);
1506     [_key getCString:kbuf];
1507     keyStr = kbuf;
1508     bufPtr = buf;
1509     strcpy(buf, "compute");       bufPtr += 7;
1510     *bufPtr = toupper(keyStr[1]); bufPtr++;
1511     strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
1512     strcpy(bufPtr, "ForKey:");
1513     if (kbuf) free(kbuf);
1514
1515 #if NeXT_RUNTIME
1516     sel = sel_getUid(buf);
1517 #else    
1518     sel = sel_get_any_uid(buf);
1519 #endif
1520     if (buf) free(buf);
1521     
1522     return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
1523   }
1524   else {
1525     /* process the _key in a map function */
1526     unsigned i, cc = [self count];
1527     NSArray  *result;
1528     id *objects;
1529     id (*objAtIdx)(id, SEL, unsigned int);
1530
1531 #if DEBUG
1532     if ([_key isEqualToString:@"count"]) {
1533       NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
1534             @"PROBABLY WANT TO USE @count INSTEAD !",
1535             __PRETTY_FUNCTION__);
1536       return [self valueForKey:@"@count"];
1537     }
1538 #endif
1539     
1540     if (cc == 0) return [NSArray array];
1541     
1542     objects = calloc(cc + 2, sizeof(id));
1543     objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
1544     
1545     for (i = 0; i < cc; i++) {
1546       register id o;
1547       
1548       o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
1549       objects[i] = o ? o : null;
1550     }
1551     
1552     result = [NSArray arrayWithObjects:objects count:cc];
1553     if (objects) free(objects);
1554     return result;
1555   }
1556 }
1557
1558 @end /* NSArray(EOKeyValueCoding) */
1559
1560 #endif /* !NeXT_Foundation_LIBRARY */