~ubuntu-branches/ubuntu/edgy/sope/edgy

« back to all changes in this revision

Viewing changes to sope-core/EOControl/EOKeyValueCoding.m

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Ley
  • Date: 2005-08-19 16:53:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050819165331-hs683wz1osm708pw
Tags: upstream-4.4rc.2
ImportĀ upstreamĀ versionĀ 4.4rc.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 = [_keyPath cString];
 
811
  if (index(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:&(buf[start]) length:(i - start)]
 
822
        : @"";
 
823
      
 
824
      if ((value = [value valueForKey:key]) == nil)
 
825
        return nil;
 
826
      
 
827
      start = (i + 1); /* next part is after the pt */
 
828
    }
 
829
  }
 
830
  /* check last part */
 
831
  {
 
832
    NSString *key;
 
833
    
 
834
    key = (start < i)
 
835
      ? [StringClass stringWithCString:&(buf[start]) length:(i - start)]
 
836
      : @"";
 
837
    return [value valueForKey:key];
 
838
  }
 
839
#else
 
840
  /* naive implementation */
 
841
  NSEnumerator *keyPath;
 
842
  NSString *key;
 
843
  id value;
 
844
  
 
845
  value   = self;
 
846
  keyPath = [[_keyPath componentsSeparatedByString:@"."] objectEnumerator];
 
847
  while ((key = [keyPath nextObject]) && (value != nil))
 
848
    value = [value valueForKey:key];
 
849
  return value;
 
850
#endif
 
851
}
 
852
 
 
853
@end /* NSObject(EOKeyPathValueCoding) */
 
854
 
 
855
@implementation NSArray(EOKeyValueCoding)
 
856
 
 
857
- (id)computeSumForKey:(NSString *)_key {
 
858
  unsigned i, cc = [self count];
 
859
  id (*objAtIdx)(id, SEL, unsigned int);
 
860
  double sum;
 
861
 
 
862
  if (cc == 0) return [NSNumber numberWithDouble:0.0];
 
863
  
 
864
  objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
 
865
    
 
866
  for (i = 0, sum = 0.0; i < cc; i++) {
 
867
    register id o;
 
868
      
 
869
    o = objAtIdx(self, @selector(objectAtIndex:), i);
 
870
    sum += [o doubleValue];
 
871
  }
 
872
  return [NSNumber numberWithDouble:sum];
 
873
}
 
874
 
 
875
- (id)computeAvgForKey:(NSString *)_key {
 
876
  unsigned i, cc = [self count];
 
877
  id (*objAtIdx)(id, SEL, unsigned int);
 
878
  double sum;
 
879
 
 
880
  if (cc == 0) return [NSNumber numberWithDouble:0.0];
 
881
  
 
882
  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
 
883
    
 
884
  for (i = 0, sum = 0.0; i < cc; i++) {
 
885
    register id o;
 
886
      
 
887
    o = objAtIdx(self, @selector(objectAtIndex:), i);
 
888
 
 
889
    sum += [o doubleValue];
 
890
  }
 
891
  return [NSNumber numberWithDouble:(sum / (double)cc)];
 
892
}
 
893
 
 
894
- (id)computeCountForKey:(NSString *)_key {
 
895
  return [NSNumber numberWithUnsignedInt:[self count]];
 
896
}
 
897
 
 
898
- (id)computeMaxForKey:(NSString *)_key {
 
899
  unsigned i, cc = [self count];
 
900
  id (*objAtIdx)(id, SEL, unsigned int);
 
901
  double max;
 
902
 
 
903
  if (cc == 0) return nil;
 
904
    
 
905
  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
 
906
 
 
907
  max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
 
908
  for (i = 1; i < cc; i++) {
 
909
    register double ov;
 
910
      
 
911
    ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
 
912
    if (ov > max) max = ov;
 
913
  }
 
914
  return [NSNumber numberWithDouble:max];
 
915
}
 
916
 
 
917
- (id)computeMinForKey:(NSString *)_key {
 
918
  unsigned i, cc = [self count];
 
919
  id (*objAtIdx)(id, SEL, unsigned int);
 
920
  double min;
 
921
 
 
922
  if (cc == 0) return nil;
 
923
  
 
924
  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
 
925
    
 
926
  min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
 
927
  for (i = 1; i < cc; i++) {
 
928
    register double ov;
 
929
      
 
930
    ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
 
931
    if (ov < min) min = ov;
 
932
  }
 
933
  return [NSNumber numberWithDouble:min];
 
934
}
 
935
 
 
936
- (id)valueForKey:(NSString *)_key {
 
937
  if ([_key hasPrefix:@"@"]) {
 
938
    /* process a computed function */
 
939
    const char *keyStr;
 
940
    char       *bufPtr;
 
941
    unsigned   keyLen = [_key cStringLength];
 
942
    char       *kbuf, *buf;
 
943
    SEL        sel;
 
944
 
 
945
    kbuf = malloc(keyLen + 4);
 
946
    buf  = malloc(keyLen + 20);
 
947
    [_key getCString:kbuf];
 
948
    keyStr = kbuf;
 
949
    bufPtr = buf;
 
950
    strcpy(buf, "compute");       bufPtr += 7;
 
951
    *bufPtr = toupper(keyStr[1]); bufPtr++;
 
952
    strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
 
953
    strcpy(bufPtr, "ForKey:");
 
954
    if (kbuf) free(kbuf);
 
955
    
 
956
    sel = sel_get_any_uid(buf);
 
957
    if (buf) free(buf);
 
958
    
 
959
    return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
 
960
  }
 
961
  else {
 
962
    /* process the _key in a map function */
 
963
    unsigned i, cc = [self count];
 
964
    id objects[cc];
 
965
    id (*objAtIdx)(id, SEL, unsigned int);
 
966
 
 
967
#if DEBUG
 
968
    if ([_key isEqualToString:@"count"]) {
 
969
      NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
 
970
            @"PROBABLY WANT TO USE @count INSTEAD !",
 
971
            __PRETTY_FUNCTION__);
 
972
      return [self valueForKey:@"@count"];
 
973
    }
 
974
#endif
 
975
    
 
976
    objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
 
977
    
 
978
    for (i = 0; i < cc; i++) {
 
979
      register id o;
 
980
      
 
981
      o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
 
982
      
 
983
      if (o)
 
984
        objects[i] = o;
 
985
      else {
 
986
        if (null == nil) null = [EONull null];
 
987
        objects[i] = null;
 
988
      }
 
989
    }
 
990
    
 
991
    return [NSArray arrayWithObjects:objects count:cc];
 
992
  }
 
993
}
 
994
 
 
995
@end /* NSArray(EOKeyValueCoding) */
 
996
 
 
997
@implementation NSDictionary(EOKeyValueCoding)
 
998
 
 
999
- (NSDictionary *)valuesForKeys:(NSArray *)keys {
 
1000
  int n = [keys count];
 
1001
 
 
1002
  if (n == 0)
 
1003
    return [NSDictionary dictionary];
 
1004
  else if (n == 1) {
 
1005
    NSString *key = [keys objectAtIndex:0];
 
1006
 
 
1007
    return [NSDictionary dictionaryWithObject:[self objectForKey:key]
 
1008
                         forKey:key];
 
1009
  }
 
1010
  else {
 
1011
    NSMutableArray *newKeys, *newVals;
 
1012
    int i;
 
1013
        
 
1014
    newKeys = [NSMutableArray arrayWithCapacity:n];
 
1015
    newVals = [NSMutableArray arrayWithCapacity:n];
 
1016
    
 
1017
    for (i = 0; i < n; i++) {
 
1018
      id key = [keys objectAtIndex:i];
 
1019
      id val = [self objectForKey:key];
 
1020
      
 
1021
      if (val) {
 
1022
        [newKeys addObject:key];
 
1023
        [newVals addObject:val];
 
1024
      }
 
1025
    }
 
1026
    
 
1027
    return [NSDictionary dictionaryWithObjects:newVals forKeys:newKeys];
 
1028
  }
 
1029
}
 
1030
 
 
1031
- (void)takeValue:(id)_value forKey:(NSString *)_key {
 
1032
  //#warning takeValue:forKey: is ignored in NSDictionaries !
 
1033
  // ignore
 
1034
  //[self handleTakeValue:_value forUnboundKey:_key];
 
1035
}
 
1036
 
 
1037
- (id)valueForKey:(id)_key {
 
1038
  id obj;
 
1039
  
 
1040
  if (_key == nil) // TODO: warn about nil key?
 
1041
    return nil;
 
1042
  if ((obj = [self objectForKey:_key]) == nil)
 
1043
    return nil;
 
1044
  
 
1045
  if (null == nil) null = [[NSNull null] retain];
 
1046
  if (obj == null)
 
1047
    return nil;
 
1048
    
 
1049
  return obj;
 
1050
}
 
1051
 
 
1052
@end /* NSDictionary(EOKeyValueCoding) */
 
1053
 
 
1054
@implementation NSMutableDictionary(EOKeyValueCoding)
 
1055
 
 
1056
- (void)takeValuesFromDictionary:(NSDictionary*)dictionary {
 
1057
  [self addEntriesFromDictionary:dictionary];
 
1058
}
 
1059
 
 
1060
- (void)takeValue:(id)_value forKey:(id)_key {
 
1061
  if (_value == nil) _value = [NSNull null];
 
1062
  [self setObject:_value forKey:_key];
 
1063
}
 
1064
 
 
1065
@end /* NSMutableDictionary(EOKeyValueCoding) */
 
1066
 
 
1067
/*
 
1068
 *  Accessor functions
 
1069
 */
 
1070
 
 
1071
/* ACCESS to keys of id type. */
 
1072
 
 
1073
static id idMethodGetFunc(void* info1, void* info2, id self) {
 
1074
  id (*fptr)(id, SEL) = (id(*)(id, SEL))info1;
 
1075
  id val = fptr(self, (SEL)info2);
 
1076
  return val;
 
1077
}
 
1078
static id idIvarGetFunc(void* info1, void* info2, id self) {
 
1079
  id* ptr = (id*)((char*)self + (int)info2);
 
1080
  return *ptr;
 
1081
}
 
1082
 
 
1083
static void idMethodSetFunc(void* info1, void* info2, id self, id val) {
 
1084
  void (*fptr)(id, SEL, id) = (void(*)(id, SEL, id))info1;
 
1085
  fptr(self, (SEL)info2, val);
 
1086
}
 
1087
 
 
1088
static void idIvarSetFunc(void* info1, void* info2, id self, id val)
 
1089
{
 
1090
  id* ptr = (id*)((char*)self + (int)info2);
 
1091
  ASSIGN(*ptr, val);
 
1092
}
 
1093
 
 
1094
/* ACCESS to keys of char type. */
 
1095
 
 
1096
static id charMethodGetFunc(void* info1, void* info2, id self)
 
1097
{
 
1098
  char (*fptr)(id, SEL) = (char(*)(id, SEL))info1;
 
1099
  char val = fptr(self, (SEL)info2);
 
1100
  return [NumberClass numberWithChar:val];
 
1101
}
 
1102
 
 
1103
static id charIvarGetFunc(void* info1, void* info2, id self)
 
1104
{
 
1105
  char* ptr = (char*)((char*)self + (int)info2);
 
1106
  return [NumberClass numberWithChar:*ptr];
 
1107
}
 
1108
 
 
1109
static void charMethodSetFunc(void* info1, void* info2, id self, id val)
 
1110
{
 
1111
  void (*fptr)(id, SEL, char) = (void(*)(id, SEL, char))info1;
 
1112
  fptr(self, (SEL)info2, [val charValue]);
 
1113
}
 
1114
 
 
1115
static void charIvarSetFunc(void* info1, void* info2, id self, id val)
 
1116
{
 
1117
  char* ptr = (char*)((char*)self + (int)info2);
 
1118
  *ptr = [val charValue];
 
1119
}
 
1120
 
 
1121
 
 
1122
/* ACCESS to keys of unsigned char type. */
 
1123
 
 
1124
static id unsignedCharMethodGetFunc(void* info1, void* info2, id self)
 
1125
{
 
1126
  unsigned char (*fptr)(id, SEL) = (unsigned char(*)(id, SEL))info1;
 
1127
  unsigned char val = fptr(self, (SEL)info2);
 
1128
  return [NumberClass numberWithUnsignedChar:val];
 
1129
}
 
1130
 
 
1131
static id unsignedCharIvarGetFunc(void* info1, void* info2, id self)
 
1132
{
 
1133
  unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
 
1134
  return [NumberClass numberWithUnsignedChar:*ptr];
 
1135
}
 
1136
 
 
1137
static void unsignedCharMethodSetFunc(void* info1, void* info2, id self, id val)
 
1138
{
 
1139
  void (*fptr)(id, SEL, unsigned char) = (void(*)(id, SEL, unsigned char))info1;
 
1140
  fptr(self, (SEL)info2, [val unsignedCharValue]);
 
1141
}
 
1142
 
 
1143
static void unsignedCharIvarSetFunc(void* info1, void* info2, id self, id val)
 
1144
{
 
1145
  unsigned char* ptr = (unsigned char*)((char*)self + (int)info2);
 
1146
  *ptr = [val unsignedCharValue];
 
1147
}
 
1148
 
 
1149
 
 
1150
/* ACCESS to keys of short type. */
 
1151
 
 
1152
static id shortMethodGetFunc(void* info1, void* info2, id self)
 
1153
{
 
1154
  short (*fptr)(id, SEL) = (short(*)(id, SEL))info1;
 
1155
  short val = fptr(self, (SEL)info2);
 
1156
  return [NumberClass numberWithShort:val];
 
1157
}
 
1158
 
 
1159
static id shortIvarGetFunc(void* info1, void* info2, id self)
 
1160
{
 
1161
  short* ptr = (short*)((char*)self + (int)info2);
 
1162
  return [NumberClass numberWithShort:*ptr];
 
1163
}
 
1164
 
 
1165
static void shortMethodSetFunc(void* info1, void* info2, id self, id val)
 
1166
{
 
1167
  void (*fptr)(id, SEL, short) = (void(*)(id, SEL, short))info1;
 
1168
  fptr(self, (SEL)info2, [val shortValue]);
 
1169
}
 
1170
 
 
1171
static void shortIvarSetFunc(void* info1, void* info2, id self, id val)
 
1172
{
 
1173
  short* ptr = (short*)((char*)self + (int)info2);
 
1174
  *ptr = [val shortValue];
 
1175
}
 
1176
 
 
1177
 
 
1178
/* ACCESS to keys of unsigned short type. */
 
1179
 
 
1180
static id unsignedShortMethodGetFunc(void* info1, void* info2, id self)
 
1181
{
 
1182
  unsigned short (*fptr)(id, SEL) = (unsigned short(*)(id, SEL))info1;
 
1183
  unsigned short val = fptr(self, (SEL)info2);
 
1184
  return [NumberClass numberWithUnsignedShort:val];
 
1185
}
 
1186
 
 
1187
static id unsignedShortIvarGetFunc(void* info1, void* info2, id self)
 
1188
{
 
1189
  unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
 
1190
  return [NumberClass numberWithUnsignedShort:*ptr];
 
1191
}
 
1192
 
 
1193
static void unsignedShortMethodSetFunc(void* info1, void* info2, id self, id val)
 
1194
{
 
1195
  void (*fptr)(id, SEL, unsigned short) = (void(*)(id, SEL, unsigned short))info1;
 
1196
  fptr(self, (SEL)info2, [val unsignedShortValue]);
 
1197
}
 
1198
 
 
1199
static void unsignedShortIvarSetFunc(void* info1, void* info2, id self, id val)
 
1200
{
 
1201
  unsigned short* ptr = (unsigned short*)((char*)self + (int)info2);
 
1202
  *ptr = [val unsignedShortValue];
 
1203
}
 
1204
 
 
1205
 
 
1206
/* ACCESS to keys of int type. */
 
1207
 
 
1208
static id intMethodGetFunc(void* info1, void* info2, id self)
 
1209
{
 
1210
  int (*fptr)(id, SEL) = (int(*)(id, SEL))info1;
 
1211
  int val = fptr(self, (SEL)info2);
 
1212
  return [NumberClass numberWithInt:val];
 
1213
}
 
1214
 
 
1215
static id intIvarGetFunc(void* info1, void* info2, id self)
 
1216
{
 
1217
  int* ptr = (int*)((char*)self + (int)info2);
 
1218
  return [NumberClass numberWithInt:*ptr];
 
1219
}
 
1220
 
 
1221
static void intMethodSetFunc(void* info1, void* info2, id self, id val)
 
1222
{
 
1223
  void (*fptr)(id, SEL, int) = (void(*)(id, SEL, int))info1;
 
1224
  fptr(self, (SEL)info2, [val intValue]);
 
1225
}
 
1226
 
 
1227
static void intIvarSetFunc(void* info1, void* info2, id self, id val)
 
1228
{
 
1229
  int* ptr = (int*)((char*)self + (int)info2);
 
1230
  *ptr = [val intValue];
 
1231
}
 
1232
 
 
1233
 
 
1234
/* ACCESS to keys of unsigned int type. */
 
1235
 
 
1236
static id unsignedIntMethodGetFunc(void* info1, void* info2, id self)
 
1237
{
 
1238
  unsigned int (*fptr)(id, SEL) = (unsigned int(*)(id, SEL))info1;
 
1239
  unsigned int val = fptr(self, (SEL)info2);
 
1240
  return [NumberClass numberWithUnsignedInt:val];
 
1241
}
 
1242
 
 
1243
static id unsignedIntIvarGetFunc(void* info1, void* info2, id self)
 
1244
{
 
1245
  unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
 
1246
  return [NumberClass numberWithUnsignedInt:*ptr];
 
1247
}
 
1248
 
 
1249
static void unsignedIntMethodSetFunc(void* info1, void* info2, id self, id val)
 
1250
{
 
1251
  void (*fptr)(id, SEL, unsigned int) = (void(*)(id, SEL, unsigned int))info1;
 
1252
  fptr(self, (SEL)info2, [val unsignedIntValue]);
 
1253
}
 
1254
 
 
1255
static void unsignedIntIvarSetFunc(void* info1, void* info2, id self, id val)
 
1256
{
 
1257
  unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
 
1258
  *ptr = [val unsignedIntValue];
 
1259
}
 
1260
 
 
1261
 
 
1262
/* ACCESS to keys of long type. */
 
1263
 
 
1264
static id longMethodGetFunc(void* info1, void* info2, id self)
 
1265
{
 
1266
  long (*fptr)(id, SEL) = (long(*)(id, SEL))info1;
 
1267
  long val = fptr(self, (SEL)info2);
 
1268
  return [NumberClass numberWithLong:val];
 
1269
}
 
1270
 
 
1271
static id longIvarGetFunc(void* info1, void* info2, id self)
 
1272
{
 
1273
  long* ptr = (long*)((char*)self + (int)info2);
 
1274
  return [NumberClass numberWithLong:*ptr];
 
1275
}
 
1276
 
 
1277
static void longMethodSetFunc(void* info1, void* info2, id self, id val)
 
1278
{
 
1279
  void (*fptr)(id, SEL, long) = (void(*)(id, SEL, long))info1;
 
1280
  fptr(self, (SEL)info2, [val longValue]);
 
1281
}
 
1282
 
 
1283
static void longIvarSetFunc(void* info1, void* info2, id self, id val)
 
1284
{
 
1285
  long* ptr = (long*)((char*)self + (int)info2);
 
1286
  *ptr = [val longValue];
 
1287
}
 
1288
 
 
1289
 
 
1290
/* unsigned long type */
 
1291
 
 
1292
static id unsignedLongMethodGetFunc(void* info1, void* info2, id self) {
 
1293
  unsigned long (*fptr)(id, SEL) = (unsigned long(*)(id, SEL))info1;
 
1294
  unsigned long val = fptr(self, (SEL)info2);
 
1295
  return [NumberClass numberWithUnsignedLong:val];
 
1296
}
 
1297
 
 
1298
static id unsignedLongIvarGetFunc(void* info1, void* info2, id self) {
 
1299
  unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
 
1300
  return [NumberClass numberWithUnsignedLong:*ptr];
 
1301
}
 
1302
 
 
1303
static void unsignedLongMethodSetFunc(void* info1, void* info2, id self, id val) {
 
1304
  void (*fptr)(id, SEL, unsigned long) = (void(*)(id, SEL, unsigned long))info1;
 
1305
  fptr(self, (SEL)info2, [val unsignedLongValue]);
 
1306
}
 
1307
 
 
1308
static void unsignedLongIvarSetFunc(void* info1, void* info2, id self, id val) {
 
1309
  unsigned long* ptr = (unsigned long*)((char*)self + (int)info2);
 
1310
  *ptr = [val unsignedLongValue];
 
1311
}
 
1312
 
 
1313
 
 
1314
/* long long type */
 
1315
 
 
1316
static id longLongMethodGetFunc(void* info1, void* info2, id self) {
 
1317
  long long (*fptr)(id, SEL) = (long long(*)(id, SEL))info1;
 
1318
  long long val = fptr(self, (SEL)info2);
 
1319
  return [NumberClass numberWithLongLong:val];
 
1320
}
 
1321
 
 
1322
static id longLongIvarGetFunc(void* info1, void* info2, id self) {
 
1323
  long long* ptr = (long long*)((char*)self + (int)info2);
 
1324
  return [NumberClass numberWithLongLong:*ptr];
 
1325
}
 
1326
 
 
1327
static void longLongMethodSetFunc(void* info1, void* info2, id self, id val) {
 
1328
  void (*fptr)(id, SEL, long long) = (void(*)(id, SEL, long long))info1;
 
1329
  fptr(self, (SEL)info2, [val longLongValue]);
 
1330
}
 
1331
 
 
1332
static void longLongIvarSetFunc(void* info1, void* info2, id self, id val) {
 
1333
  long long* ptr = (long long*)((char*)self + (int)info2);
 
1334
  *ptr = [val longLongValue];
 
1335
}
 
1336
 
 
1337
 
 
1338
/* unsigned long long type */
 
1339
 
 
1340
static id unsignedLongLongMethodGetFunc(void* info1, void* info2, id self) {
 
1341
  unsigned long long (*fptr)(id, SEL) = (unsigned long long(*)(id, SEL))info1;
 
1342
  unsigned long long val = fptr(self, (SEL)info2);
 
1343
  return [NumberClass numberWithUnsignedLongLong:val];
 
1344
}
 
1345
 
 
1346
static id unsignedLongLongIvarGetFunc(void* info1, void* info2, id self) {
 
1347
  unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
 
1348
  return [NumberClass numberWithUnsignedLongLong:*ptr];
 
1349
}
 
1350
 
 
1351
static void unsignedLongLongMethodSetFunc(void* info1, void* info2, id self, id val) {
 
1352
  void (*fptr)(id, SEL, unsigned long long) = (void(*)(id, SEL, unsigned long long))info1;
 
1353
  fptr(self, (SEL)info2, [val unsignedLongLongValue]);
 
1354
}
 
1355
 
 
1356
static void unsignedLongLongIvarSetFunc(void* info1, void* info2, id self, id val) {
 
1357
  unsigned long long* ptr = (unsigned long long*)((char*)self + (int)info2);
 
1358
  *ptr = [val unsignedLongLongValue];
 
1359
}
 
1360
 
 
1361
 
 
1362
/* float */
 
1363
 
 
1364
static id floatMethodGetFunc(void* info1, void* info2, id self) {
 
1365
  float (*fptr)(id, SEL) = (float(*)(id, SEL))info1;
 
1366
  float val = fptr(self, (SEL)info2);
 
1367
  return [NumberClass numberWithFloat:val];
 
1368
}
 
1369
 
 
1370
static id floatIvarGetFunc(void* info1, void* info2, id self) {
 
1371
  float* ptr = (float*)((char*)self + (int)info2);
 
1372
  return [NumberClass numberWithFloat:*ptr];
 
1373
}
 
1374
 
 
1375
static void floatMethodSetFunc(void* info1, void* info2, id self, id val) {
 
1376
  void (*fptr)(id, SEL, float) = (void(*)(id, SEL, float))info1;
 
1377
  fptr(self, (SEL)info2, [val floatValue]);
 
1378
}
 
1379
 
 
1380
static void floatIvarSetFunc(void* info1, void* info2, id self, id val) {
 
1381
  float* ptr = (float*)((char*)self + (int)info2);
 
1382
  *ptr = [val floatValue];
 
1383
}
 
1384
 
 
1385
 
 
1386
/* double */
 
1387
 
 
1388
static id doubleMethodGetFunc(void* info1, void* info2, id self) {
 
1389
  double (*fptr)(id, SEL) = (double(*)(id, SEL))info1;
 
1390
  double val = fptr(self, (SEL)info2);
 
1391
  return [NumberClass numberWithDouble:val];
 
1392
}
 
1393
 
 
1394
static id doubleIvarGetFunc(void* info1, void* info2, id self) {
 
1395
  double* ptr = (double*)((char*)self + (int)info2);
 
1396
  return [NumberClass numberWithDouble:*ptr];
 
1397
}
 
1398
 
 
1399
static void doubleMethodSetFunc(void* info1, void* info2, id self, id val) {
 
1400
  void (*fptr)(id, SEL, double) = (void(*)(id, SEL, double))info1;
 
1401
  fptr(self, (SEL)info2, [val doubleValue]);
 
1402
}
 
1403
 
 
1404
static void doubleIvarSetFunc(void* info1, void* info2, id self, id val) {
 
1405
  double* ptr = (double*)((char*)self + (int)info2);
 
1406
  *ptr = [val doubleValue];
 
1407
}
 
1408
 
 
1409
#else /* NeXT_Foundation_LIBRARY */
 
1410
 
 
1411
@implementation NSArray(EOKeyValueCoding)
 
1412
 
 
1413
- (id)computeSumForKey:(NSString *)_key {
 
1414
  unsigned i, cc = [self count];
 
1415
  id (*objAtIdx)(id, SEL, unsigned int);
 
1416
  double sum;
 
1417
 
 
1418
  if (cc == 0) return [NSNumber numberWithDouble:0.0];
 
1419
  
 
1420
  objAtIdx = (void*)[self methodForSelector:@selector(objectAtIndex:)];
 
1421
    
 
1422
  for (i = 0, sum = 0.0; i < cc; i++) {
 
1423
    register id o;
 
1424
      
 
1425
    o = objAtIdx(self, @selector(objectAtIndex:), i);
 
1426
    sum += [o doubleValue];
 
1427
  }
 
1428
  return [NSNumber numberWithDouble:sum];
 
1429
}
 
1430
 
 
1431
- (id)computeAvgForKey:(NSString *)_key {
 
1432
  unsigned i, cc = [self count];
 
1433
  id (*objAtIdx)(id, SEL, unsigned int);
 
1434
  double sum;
 
1435
 
 
1436
  if (cc == 0) return [NSNumber numberWithDouble:0.0];
 
1437
  
 
1438
  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
 
1439
    
 
1440
  for (i = 0, sum = 0.0; i < cc; i++) {
 
1441
    register id o;
 
1442
      
 
1443
    o = objAtIdx(self, @selector(objectAtIndex:), i);
 
1444
 
 
1445
    sum += [o doubleValue];
 
1446
  }
 
1447
  return [NSNumber numberWithDouble:(sum / (double)cc)];
 
1448
}
 
1449
 
 
1450
- (id)computeCountForKey:(NSString *)_key {
 
1451
  return [NSNumber numberWithUnsignedInt:[self count]];
 
1452
}
 
1453
 
 
1454
- (id)computeMaxForKey:(NSString *)_key {
 
1455
  unsigned i, cc = [self count];
 
1456
  id (*objAtIdx)(id, SEL, unsigned int);
 
1457
  double max;
 
1458
 
 
1459
  if (cc == 0) return nil;
 
1460
    
 
1461
  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
 
1462
 
 
1463
  max = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
 
1464
  for (i = 1; i < cc; i++) {
 
1465
    register double ov;
 
1466
      
 
1467
    ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
 
1468
    if (ov > max) max = ov;
 
1469
  }
 
1470
  return [NSNumber numberWithDouble:max];
 
1471
}
 
1472
 
 
1473
- (id)computeMinForKey:(NSString *)_key {
 
1474
  unsigned i, cc = [self count];
 
1475
  id (*objAtIdx)(id, SEL, unsigned int);
 
1476
  double min;
 
1477
 
 
1478
  if (cc == 0) return nil;
 
1479
  
 
1480
  objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
 
1481
    
 
1482
  min = [objAtIdx(self, @selector(objectAtIndex:), 0) doubleValue];
 
1483
  for (i = 1; i < cc; i++) {
 
1484
    register double ov;
 
1485
      
 
1486
    ov = [objAtIdx(self, @selector(objectAtIndex:), i) doubleValue];
 
1487
    if (ov < min) min = ov;
 
1488
  }
 
1489
  return [NSNumber numberWithDouble:min];
 
1490
}
 
1491
 
 
1492
- (id)valueForKey:(NSString *)_key {
 
1493
  if (null == nil) null = [[EONull null] retain];
 
1494
  
 
1495
  if ([_key hasPrefix:@"@"]) {
 
1496
    /* process a computed function */
 
1497
    const char *keyStr;
 
1498
    char       *bufPtr;
 
1499
    unsigned   keyLen = [_key cStringLength];
 
1500
    char       *kbuf, *buf;
 
1501
    SEL        sel;
 
1502
 
 
1503
    kbuf = malloc(keyLen + 1);
 
1504
    buf  = malloc(keyLen + 16);
 
1505
    [_key getCString:kbuf];
 
1506
    keyStr = kbuf;
 
1507
    bufPtr = buf;
 
1508
    strcpy(buf, "compute");       bufPtr += 7;
 
1509
    *bufPtr = toupper(keyStr[1]); bufPtr++;
 
1510
    strncpy(&(buf[8]), &(keyStr[2]), keyLen - 2); bufPtr += (keyLen - 2);
 
1511
    strcpy(bufPtr, "ForKey:");
 
1512
    if (kbuf) free(kbuf);
 
1513
 
 
1514
#if NeXT_RUNTIME
 
1515
    sel = sel_getUid(buf);
 
1516
#else    
 
1517
    sel = sel_get_any_uid(buf);
 
1518
#endif
 
1519
    if (buf) free(buf);
 
1520
    
 
1521
    return sel != NULL ? [self performSelector:sel withObject:_key] : nil;
 
1522
  }
 
1523
  else {
 
1524
    /* process the _key in a map function */
 
1525
    unsigned i, cc = [self count];
 
1526
    NSArray  *result;
 
1527
    id *objects;
 
1528
    id (*objAtIdx)(id, SEL, unsigned int);
 
1529
 
 
1530
#if DEBUG
 
1531
    if ([_key isEqualToString:@"count"]) {
 
1532
      NSLog(@"WARNING(%s): USED -valueForKey(@\"count\") ON NSArray, YOU"
 
1533
            @"PROBABLY WANT TO USE @count INSTEAD !",
 
1534
            __PRETTY_FUNCTION__);
 
1535
      return [self valueForKey:@"@count"];
 
1536
    }
 
1537
#endif
 
1538
    
 
1539
    if (cc == 0) return [NSArray array];
 
1540
    
 
1541
    objects = calloc(cc + 2, sizeof(id));
 
1542
    objAtIdx = (void *)[self methodForSelector:@selector(objectAtIndex:)];
 
1543
    
 
1544
    for (i = 0; i < cc; i++) {
 
1545
      register id o;
 
1546
      
 
1547
      o = [objAtIdx(self, @selector(objectAtIndex:), i) valueForKey:_key];
 
1548
      objects[i] = o ? o : null;
 
1549
    }
 
1550
    
 
1551
    result = [NSArray arrayWithObjects:objects count:cc];
 
1552
    if (objects) free(objects);
 
1553
    return result;
 
1554
  }
 
1555
}
 
1556
 
 
1557
@end /* NSArray(EOKeyValueCoding) */
 
1558
 
 
1559
#endif /* !NeXT_Foundation_LIBRARY */