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