mirror of
https://github.com/gnustep/libs-gdl2.git
synced 2025-02-15 16:10:46 +00:00
* EOControl/EOFault.m, * EOControl/EOFaultHandler.m, * EOControl/EOKeyComparisonQualifier.m, * EOControl/EOKeyValueArchiver.m, * EOControl/EOKeyValueCoding.m, * EOControl/EOKeyValueCodingBase.m, * EOControl/EOMutableKnownKeyDictionary.h, * EOControl/EONotQualifier.m, * EOControl/EOOrQualifier.m, * EOControl/EOQualifier.m, * EOAccess/EOAdaptor.m, * EOAccess/EOAdaptorContext.m, * EOAccess/EOAttribute.m, * EOAccess/EODatabase.m, * EOAccess/EODatabaseContext.m, * EOAccess/EOExpressionArray.m, * EOAccess/EOJoin.m, * EOAccess/EOModel.m, * EOAccess/EOModelGroup.m, * EOAccess/EORelationship.m, * EOAccess/EOSQLExpression.m, * EOAccess/EOSQLQualifier.m, * EOAccess/EOSchemaGeneration.m, * EOAccess/EOStoredProcedure.m, * EOAdaptors/PostgreSQLAdaptor/PostgreSQLAdaptor.m, * EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m, * EOAdaptors/PostgreSQLAdaptor/PostgreSQLExpression.m, * EOAdaptors/SQLiteAdaptor/SQLite3Adaptor.m, * EOAdaptors/SQLiteAdaptor/SQLite3Channel.m, * EOInterface/EOTableViewAssociation.m, * EOModeler/EOModelExtensions.m, * EOModeler/EOModelerApp.m, * DBModeler/ModelerAttributeEditor.m, * DBModeler/ModelerEntityEditor.m: Remove references to NSUtilities.h. Add includes for missing header references. * DBModeler/Modeler.m (-[showEditor:]): Add cast to avoid compiler warning. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gdl2/trunk@25994 72102866-910b-0410-8b05-ffd578937521
1987 lines
49 KiB
Objective-C
1987 lines
49 KiB
Objective-C
/**
|
|
EOKeyValueCodingBase.m
|
|
|
|
Copyright (C) 1996-2002 Free Software Foundation, Inc.
|
|
|
|
Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
|
|
Date: November 1996
|
|
|
|
Author: Mirko Viviani <mirko.viviani@gmail.com>
|
|
Date: February 2000
|
|
|
|
$Revision$
|
|
$Date$
|
|
|
|
<abstract></abstract>
|
|
|
|
This file is part of the GNUstep Database Library.
|
|
|
|
<license>
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 3 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; see the file COPYING.LIB.
|
|
If not, write to the Free Software Foundation,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
</license>
|
|
**/
|
|
|
|
#include "config.h"
|
|
|
|
RCS_ID("$Id$")
|
|
|
|
#import <Foundation/NSObject.h>
|
|
#import <Foundation/NSArray.h>
|
|
#import <Foundation/NSDictionary.h>
|
|
#import <Foundation/NSString.h>
|
|
#import <Foundation/NSValue.h>
|
|
#import <Foundation/NSHashTable.h>
|
|
#import <Foundation/NSException.h>
|
|
#import <Foundation/NSObjCRuntime.h>
|
|
#import <Foundation/NSMapTable.h>
|
|
#import <Foundation/NSDecimalNumber.h>
|
|
#import <Foundation/NSDebug.h>
|
|
#import <Foundation/NSException.h>
|
|
|
|
#include <objc/objc-api.h>
|
|
|
|
#if !FOUNDATION_HAS_KVC
|
|
|
|
#import <EOControl/EOControl.h>
|
|
#import <EOControl/EOKeyValueCoding.h>
|
|
|
|
|
|
/*
|
|
* EOKeyValueCoding implementation
|
|
*/
|
|
|
|
NSString *EOUnknownKeyException = @"EOUnknownKeyException";
|
|
NSString *EOTargetObjectUserInfoKey = @"EOTargetObjectUserInfoKey";
|
|
NSString *EOUnknownUserInfoKey = @"EOUnknownUserInfoKey";
|
|
|
|
@implementation NSObject (EOKVCPAdditions)
|
|
|
|
/*
|
|
* Accessor functions
|
|
*/
|
|
|
|
/* ACCESS to keys of id type. */
|
|
|
|
static id idMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
id (*fptr)(id, SEL) = (id(*)(id, SEL))info1;
|
|
id val = fptr(self, (SEL)info2);
|
|
|
|
return val;
|
|
}
|
|
|
|
static id idIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
id *ptr = (id*)((char*)self + (int)info2);
|
|
|
|
return *ptr;
|
|
}
|
|
|
|
static void idMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, id) = (void(*)(id, SEL, id))info1;
|
|
|
|
fptr(self, (SEL)info2, val);
|
|
}
|
|
|
|
static void idIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
id *ptr = (id*)((char*)self + (int)info2);
|
|
|
|
[*ptr autorelease];
|
|
*ptr = [val retain];
|
|
}
|
|
|
|
/* ACCESS to keys of char type. */
|
|
|
|
static id charMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
char (*fptr)(id, SEL) = (char(*)(id, SEL))info1;
|
|
char val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithChar: val];
|
|
}
|
|
|
|
static id charIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
char *ptr = (char*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithChar: *ptr];
|
|
}
|
|
|
|
static void charMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, char) = (void(*)(id, SEL, char))info1;
|
|
|
|
fptr(self, (SEL)info2, [val charValue]);
|
|
}
|
|
|
|
static void charIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
char *ptr = (char*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val charValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of unsigned char type. */
|
|
|
|
static id unsignedCharMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned char (*fptr)(id, SEL) = (unsigned char(*)(id, SEL))info1;
|
|
unsigned char val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithUnsignedChar: val];
|
|
}
|
|
|
|
static id unsignedCharIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned char *ptr = (unsigned char*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithUnsignedChar: *ptr];
|
|
}
|
|
|
|
static void unsignedCharMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, unsigned char) = (void(*)(id, SEL, unsigned char))info1;
|
|
|
|
fptr(self, (SEL)info2, [val unsignedCharValue]);
|
|
}
|
|
|
|
static void unsignedCharIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
unsigned char *ptr = (unsigned char*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val unsignedCharValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of short type. */
|
|
|
|
static id shortMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
short (*fptr)(id, SEL) = (short(*)(id, SEL))info1;
|
|
short val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithShort: val];
|
|
}
|
|
|
|
static id shortIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
short *ptr = (short*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithShort: *ptr];
|
|
}
|
|
|
|
static void shortMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, short) = (void(*)(id, SEL, short))info1;
|
|
|
|
fptr(self, (SEL)info2, [val shortValue]);
|
|
}
|
|
|
|
static void shortIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
short* ptr = (short*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val shortValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of unsigned short type. */
|
|
|
|
static id unsignedShortMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned short (*fptr)(id, SEL) = (unsigned short(*)(id, SEL))info1;
|
|
unsigned short val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithUnsignedShort: val];
|
|
}
|
|
|
|
static id unsignedShortIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned short *ptr = (unsigned short*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithUnsignedShort: *ptr];
|
|
}
|
|
|
|
static void unsignedShortMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, unsigned short) = (void(*)(id, SEL, unsigned short))info1;
|
|
|
|
fptr(self, (SEL)info2, [val unsignedShortValue]);
|
|
}
|
|
|
|
static void unsignedShortIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
unsigned short *ptr = (unsigned short*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val unsignedShortValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of int type. */
|
|
|
|
static id intMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
int (*fptr)(id, SEL) = (int(*)(id, SEL))info1;
|
|
int val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithInt: val];
|
|
}
|
|
|
|
static id intIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
int *ptr = (int*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithInt: *ptr];
|
|
}
|
|
|
|
static void intMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, int) = (void(*)(id, SEL, int))info1;
|
|
|
|
fptr(self, (SEL)info2, [val intValue]);
|
|
}
|
|
|
|
static void intIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
int *ptr = (int*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val intValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of unsigned int type. */
|
|
|
|
static id unsignedIntMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned int (*fptr)(id, SEL) = (unsigned int(*)(id, SEL))info1;
|
|
unsigned int val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithUnsignedInt: val];
|
|
}
|
|
|
|
static id unsignedIntIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned int *ptr = (unsigned int*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithUnsignedInt: *ptr];
|
|
}
|
|
|
|
static void unsignedIntMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, unsigned int) = (void(*)(id, SEL, unsigned int))info1;
|
|
|
|
fptr(self, (SEL)info2, [val unsignedIntValue]);
|
|
}
|
|
|
|
static void unsignedIntIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
unsigned int* ptr = (unsigned int*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val unsignedIntValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of long type. */
|
|
|
|
static id longMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
long (*fptr)(id, SEL) = (long(*)(id, SEL))info1;
|
|
long val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithLong: val];
|
|
}
|
|
|
|
static id longIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
long *ptr = (long*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithLong: *ptr];
|
|
}
|
|
|
|
static void longMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, long) = (void(*)(id, SEL, long))info1;
|
|
|
|
fptr(self, (SEL)info2, [val longValue]);
|
|
}
|
|
|
|
static void longIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
long *ptr = (long*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val longValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of unsigned long type. */
|
|
|
|
static id unsignedLongMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned long (*fptr)(id, SEL) = (unsigned long(*)(id, SEL))info1;
|
|
unsigned long val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithUnsignedLong: val];
|
|
}
|
|
|
|
static id unsignedLongIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned long *ptr = (unsigned long*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithUnsignedLong: *ptr];
|
|
}
|
|
|
|
static void unsignedLongMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, unsigned long) = (void(*)(id, SEL, unsigned long))info1;
|
|
|
|
fptr(self, (SEL)info2, [val unsignedLongValue]);
|
|
}
|
|
|
|
static void unsignedLongIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
unsigned long *ptr = (unsigned long*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val unsignedLongValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of long long type. */
|
|
|
|
static id longLongMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
long long (*fptr)(id, SEL) = (long long(*)(id, SEL))info1;
|
|
long long val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithLongLong: val];
|
|
}
|
|
|
|
static id longLongIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
long long *ptr = (long long*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithLongLong: *ptr];
|
|
}
|
|
|
|
static void longLongMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, long long) = (void(*)(id, SEL, long long))info1;
|
|
|
|
fptr(self, (SEL)info2, [val longLongValue]);
|
|
}
|
|
|
|
static void longLongIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
long long *ptr = (long long*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val longLongValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of unsigned long long type. */
|
|
|
|
static id unsignedLongLongMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned long long (*fptr)(id, SEL) = (unsigned long long(*)(id, SEL))info1;
|
|
unsigned long long val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithUnsignedLongLong: val];
|
|
}
|
|
|
|
static id unsignedLongLongIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
unsigned long long *ptr = (unsigned long long*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithUnsignedLongLong: *ptr];
|
|
}
|
|
|
|
static void unsignedLongLongMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, unsigned long long) = (void(*)(id, SEL, unsigned long long))info1;
|
|
|
|
fptr(self, (SEL)info2, [val unsignedLongLongValue]);
|
|
}
|
|
|
|
static void unsignedLongLongIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
unsigned long long *ptr = (unsigned long long*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val unsignedLongLongValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of float type. */
|
|
|
|
static id floatMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
float (*fptr)(id, SEL) = (float(*)(id, SEL))info1;
|
|
float val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithFloat: val];
|
|
}
|
|
|
|
static id floatIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
float *ptr = (float*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithFloat: *ptr];
|
|
}
|
|
|
|
static void floatMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, float) = (void(*)(id, SEL, float))info1;
|
|
|
|
fptr(self, (SEL)info2, [val floatValue]);
|
|
}
|
|
|
|
static void floatIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
float *ptr = (float*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val floatValue];
|
|
}
|
|
|
|
|
|
/* ACCESS to keys of double type. */
|
|
|
|
static id doubleMethodGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
double (*fptr)(id, SEL) = (double(*)(id, SEL))info1;
|
|
double val = fptr(self, (SEL)info2);
|
|
|
|
return [NSNumber numberWithDouble: val];
|
|
}
|
|
|
|
static id doubleIvarGetFunc(void *info1, void *info2, id self)
|
|
{
|
|
double *ptr = (double*)((char*)self + (int)info2);
|
|
|
|
return [NSNumber numberWithDouble: *ptr];
|
|
}
|
|
|
|
static void doubleMethodSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
void (*fptr)(id, SEL, double) = (void(*)(id, SEL, double))info1;
|
|
|
|
fptr(self, (SEL)info2, [val doubleValue]);
|
|
}
|
|
|
|
static void doubleIvarSetFunc(void *info1, void *info2, id self, id val)
|
|
{
|
|
double *ptr = (double*)((char*)self + (int)info2);
|
|
|
|
*ptr = [val doubleValue];
|
|
}
|
|
|
|
/*
|
|
* Types
|
|
*/
|
|
|
|
typedef struct _KeyValueMethod
|
|
{
|
|
NSString *key;
|
|
Class class;
|
|
} KeyValueMethod;
|
|
|
|
typedef struct _GetKeyValueBinding
|
|
{
|
|
id (*access)(void*, void*, id);
|
|
void *info1;
|
|
void *info2;
|
|
} GetKeyValueBinding;
|
|
|
|
typedef struct _SetKeyValueBinding
|
|
{
|
|
void (*access)(void*, void*, id, id);
|
|
void *info1;
|
|
void *info2;
|
|
} SetKeyValueBinding;
|
|
|
|
/*
|
|
* Globals
|
|
*/
|
|
|
|
static NSMapTable *getValueBindings = NULL;
|
|
static NSMapTable *setValueBindings = NULL;
|
|
static NSMapTable *getStoredValueBindings = NULL;
|
|
static NSMapTable *setStoredValueBindings = NULL;
|
|
static BOOL keyValueDebug = NO;
|
|
static BOOL keyValueInit = NO;
|
|
|
|
/*
|
|
* KeyValueMapping
|
|
*/
|
|
|
|
static GetKeyValueBinding *newGetBinding(NSString *key, id instance)
|
|
{
|
|
GetKeyValueBinding *ret = NULL;
|
|
void *info1 = NULL;
|
|
void *info2 = NULL;
|
|
BOOL accessInstanceVariables;
|
|
id (*fptr)(void*, void*, id) = NULL;
|
|
int count;
|
|
|
|
Class class = [instance class];
|
|
MetaClass mclass = class_get_meta_class(class);
|
|
const char *ckey = [key cString];
|
|
char iname[strlen(ckey) + 4];
|
|
SEL sel;
|
|
struct objc_method *mth;
|
|
|
|
accessInstanceVariables = [NSObject accessInstanceVariablesDirectly];
|
|
|
|
// Lookup method name [- (type)key]
|
|
// Lookup method name [- (type)getKey]
|
|
count = 2;
|
|
|
|
while (!fptr && count--)
|
|
{
|
|
if (count == 1)
|
|
{
|
|
strcpy(iname, ckey);
|
|
}
|
|
else
|
|
{
|
|
strcpy(iname, "get");
|
|
strcat(iname, ckey);
|
|
iname[3] = islower(iname[3]) ? toupper(iname[3]) : iname[3];
|
|
}
|
|
|
|
sel = sel_get_any_uid(iname);
|
|
|
|
if (sel && ((mth = class_get_instance_method(class, sel))
|
|
|| (mth = class_get_class_method(mclass, sel)))
|
|
&& method_get_number_of_arguments(mth) == 2)
|
|
{
|
|
switch (*objc_skip_type_qualifiers(mth->method_types))
|
|
{
|
|
case _C_CLASS:
|
|
fptr = (id (*)(void*, void*, id))idMethodGetFunc;
|
|
break;
|
|
case _C_ID:
|
|
fptr = (id (*)(void*, void*, id))idMethodGetFunc;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (id (*)(void*, void*, id))charMethodGetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (id (*)(void*, void*, id))shortMethodGetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (id (*)(void*, void*, id))intMethodGetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (id (*)(void*, void*, id))longMethodGetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (id (*)(void*, void*, id))longLongMethodGetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (id (*)(void*, void*, id))floatMethodGetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (id (*)(void*, void*, id))doubleMethodGetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info1 = (void*)(mth->method_imp);
|
|
info2 = (void*)(mth->method_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// NSDebugFLog(@"accessInstanceVariables=%d",accessInstanceVariables);
|
|
// Lookup ivar name
|
|
|
|
if (!fptr && accessInstanceVariables == YES)
|
|
{
|
|
int keyType=0;
|
|
|
|
for (keyType = 0; !fptr && keyType < 2; keyType++)
|
|
{
|
|
const char *testKey = ckey;
|
|
char *testKeyDup = NULL;
|
|
|
|
if (keyType==1)
|
|
{
|
|
int len=strlen(testKey);
|
|
|
|
testKeyDup = malloc(len + 2);
|
|
|
|
testKeyDup[0] = '_';
|
|
strcpy(testKeyDup + 1,testKey);
|
|
|
|
testKey = testKeyDup;
|
|
}
|
|
|
|
class = [instance class];
|
|
// NSDebugFLog(@"testKey=%s",testKey);
|
|
|
|
while (!fptr && class)
|
|
{
|
|
int i;
|
|
|
|
// NSDebugFLog(@"class=%@",NSStringFromClass(class));
|
|
for (i = 0;!fptr && class->ivars && i < class->ivars->ivar_count; i++)
|
|
{
|
|
if (!strcmp(testKey, class->ivars->ivar_list[i].ivar_name))
|
|
{
|
|
// NSDebugFLog(@"Found");
|
|
switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type))
|
|
{
|
|
case _C_ID:
|
|
fptr = (id (*)(void*, void*, id))idIvarGetFunc;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (id (*)(void*, void*, id))charIvarGetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (id (*)(void*, void*, id))unsignedCharIvarGetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (id (*)(void*, void*, id))shortIvarGetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (id (*)(void*, void*, id))unsignedShortIvarGetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (id (*)(void*, void*, id))intIvarGetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (id (*)(void*, void*, id))unsignedIntIvarGetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (id (*)(void*, void*, id))longIvarGetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (id (*)(void*, void*, id))unsignedLongIvarGetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (id (*)(void*, void*, id))longLongIvarGetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (id (*)(void*, void*, id))unsignedLongLongIvarGetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (id (*)(void*, void*, id))floatIvarGetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (id (*)(void*, void*, id))doubleIvarGetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
class = class->super_class;
|
|
}
|
|
|
|
if (testKeyDup)
|
|
{
|
|
free(testKeyDup);
|
|
testKeyDup=NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// NSDebugFLog(@"fptr=%p",fptr);
|
|
|
|
// Make binding and insert into map
|
|
|
|
if (fptr)
|
|
{
|
|
KeyValueMethod* mkey = NSZoneMalloc(NSDefaultMallocZone(), sizeof(KeyValueMethod));
|
|
GetKeyValueBinding* bin = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GetKeyValueBinding));
|
|
|
|
mkey->key = [key copy];
|
|
mkey->class = [instance class];
|
|
|
|
bin->access = fptr;
|
|
bin->info1 = info1;
|
|
bin->info2 = info2;
|
|
|
|
NSMapInsert(getValueBindings, mkey, bin);
|
|
ret = bin;
|
|
}
|
|
|
|
// If no way to access value warn
|
|
if (!ret && keyValueDebug)
|
|
NSLog(@"cannnot get key `%@' for instance of class `%@'",
|
|
key, NSStringFromClass([instance class]));
|
|
|
|
return ret;
|
|
}
|
|
|
|
static GetKeyValueBinding *newGetStoredBinding(NSString *key, id instance)
|
|
{
|
|
GetKeyValueBinding *ret = NULL;
|
|
void *info1 = NULL;
|
|
void *info2 = NULL;
|
|
BOOL accessInstanceVariables;
|
|
id (*fptr)(void*, void*, id) = NULL;
|
|
int count;
|
|
|
|
Class class = [instance class];
|
|
MetaClass mclass = class_get_meta_class(class);
|
|
const char *ckey = [key cString];
|
|
char iname[strlen(ckey) + 5];
|
|
SEL sel;
|
|
struct objc_method *mth;
|
|
|
|
accessInstanceVariables = [NSObject accessInstanceVariablesDirectly];
|
|
|
|
// Lookup method name [- (type)_key]
|
|
// Lookup method name [- (type)_getKey]
|
|
count = 2;
|
|
|
|
while (!fptr && count--)
|
|
{
|
|
if(count == 1)
|
|
{
|
|
strcpy(iname, "_");
|
|
strcat(iname, ckey);
|
|
}
|
|
else
|
|
{
|
|
strcpy(iname, "_get");
|
|
strcat(iname, ckey);
|
|
iname[4] = islower(iname[4]) ? toupper(iname[4]) : iname[4];
|
|
}
|
|
|
|
sel = sel_get_any_uid(iname);
|
|
|
|
if (sel && ((mth = class_get_instance_method(class, sel))
|
|
|| (mth = class_get_class_method(mclass, sel)))
|
|
&& method_get_number_of_arguments(mth) == 2)
|
|
{
|
|
switch (*objc_skip_type_qualifiers(mth->method_types))
|
|
{
|
|
case _C_CLASS:
|
|
fptr = (id (*)(void*, void*, id))idMethodGetFunc;
|
|
break;
|
|
case _C_ID:
|
|
fptr = (id (*)(void*, void*, id))idMethodGetFunc;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (id (*)(void*, void*, id))charMethodGetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (id (*)(void*, void*, id))shortMethodGetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (id (*)(void*, void*, id))intMethodGetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (id (*)(void*, void*, id))longMethodGetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (id (*)(void*, void*, id))longLongMethodGetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (id (*)(void*, void*, id))floatMethodGetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (id (*)(void*, void*, id))doubleMethodGetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info1 = (void*)(mth->method_imp);
|
|
info2 = (void*)(mth->method_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lookup ivar name
|
|
count = 2;
|
|
|
|
while (!fptr && count-- && accessInstanceVariables == YES)
|
|
{
|
|
int i;
|
|
|
|
// Make ivar from name
|
|
if(count == 1)
|
|
{
|
|
strcpy(iname, "_");
|
|
strcat(iname, ckey);
|
|
}
|
|
else
|
|
{
|
|
strcpy(iname, ckey);
|
|
}
|
|
|
|
while (class)
|
|
{
|
|
for (i = 0; class->ivars && i < class->ivars->ivar_count; i++)
|
|
{
|
|
if (!strcmp(iname, class->ivars->ivar_list[i].ivar_name))
|
|
{
|
|
switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type))
|
|
{
|
|
case _C_ID:
|
|
fptr = (id (*)(void*, void*, id))idIvarGetFunc;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (id (*)(void*, void*, id))charIvarGetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (id (*)(void*, void*, id))unsignedCharIvarGetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (id (*)(void*, void*, id))shortIvarGetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (id (*)(void*, void*, id))unsignedShortIvarGetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (id (*)(void*, void*, id))intIvarGetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (id (*)(void*, void*, id))unsignedIntIvarGetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (id (*)(void*, void*, id))longIvarGetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (id (*)(void*, void*, id))unsignedLongIvarGetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (id (*)(void*, void*, id))longLongIvarGetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (id (*)(void*, void*, id))unsignedLongLongIvarGetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (id (*)(void*, void*, id))floatIvarGetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (id (*)(void*, void*, id))doubleIvarGetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
class = class->super_class;
|
|
}
|
|
}
|
|
|
|
// Lookup method name [- (type)key]
|
|
// Lookup method name [- (type)getKey]
|
|
count = 2;
|
|
class = [instance class];
|
|
|
|
while (!fptr && count--)
|
|
{
|
|
if (count == 1)
|
|
{
|
|
strcpy(iname, ckey);
|
|
}
|
|
else
|
|
{
|
|
strcpy(iname, "get");
|
|
strcat(iname, ckey);
|
|
iname[3] = islower(iname[3]) ? toupper(iname[3]) : iname[3];
|
|
}
|
|
|
|
sel = sel_get_any_uid(iname);
|
|
|
|
if (sel && ((mth = class_get_instance_method(class, sel))
|
|
|| (mth = class_get_class_method(mclass, sel)))
|
|
&& method_get_number_of_arguments(mth) == 2)
|
|
{
|
|
switch (*objc_skip_type_qualifiers(mth->method_types))
|
|
{
|
|
case _C_ID:
|
|
fptr = (id (*)(void*, void*, id))idMethodGetFunc;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (id (*)(void*, void*, id))charMethodGetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (id (*)(void*, void*, id))unsignedCharMethodGetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (id (*)(void*, void*, id))shortMethodGetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (id (*)(void*, void*, id))unsignedShortMethodGetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (id (*)(void*, void*, id))intMethodGetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (id (*)(void*, void*, id))unsignedIntMethodGetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (id (*)(void*, void*, id))longMethodGetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (id (*)(void*, void*, id))unsignedLongMethodGetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (id (*)(void*, void*, id))longLongMethodGetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (id (*)(void*, void*, id))unsignedLongLongMethodGetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (id (*)(void*, void*, id))floatMethodGetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (id (*)(void*, void*, id))doubleMethodGetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info1 = (void*)(mth->method_imp);
|
|
info2 = (void*)(mth->method_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make binding and insert into map
|
|
if (fptr)
|
|
{
|
|
KeyValueMethod* mkey = NSZoneMalloc(NSDefaultMallocZone(), sizeof(KeyValueMethod));
|
|
GetKeyValueBinding* bin = NSZoneMalloc(NSDefaultMallocZone(), sizeof(GetKeyValueBinding));
|
|
|
|
mkey->key = [key copy];
|
|
mkey->class = [instance class];
|
|
|
|
bin->access = fptr;
|
|
bin->info1 = info1;
|
|
bin->info2 = info2;
|
|
|
|
NSMapInsert(getStoredValueBindings, mkey, bin);
|
|
ret = bin;
|
|
}
|
|
|
|
// If no way to access value warn
|
|
if (!ret && keyValueDebug)
|
|
NSLog(@"cannnot get key `%@' for instance of class `%@'",
|
|
key, NSStringFromClass([instance class]));
|
|
|
|
return ret;
|
|
}
|
|
|
|
static SetKeyValueBinding *newSetBinding(NSString *key, id instance, id value)
|
|
{
|
|
SetKeyValueBinding *ret = NULL;
|
|
void *info1 = NULL;
|
|
void *info2 = NULL;
|
|
void (*fptr)(void*, void*, id, id) = NULL;
|
|
BOOL idMethod = NO;
|
|
|
|
// Lookup method name [-(void)setKey:(type)arg]
|
|
{
|
|
Class class = [instance class];
|
|
const char *ckey = [key cString];
|
|
SEL sel;
|
|
struct objc_method *mth;
|
|
char sname[strlen(ckey)+7];
|
|
|
|
// Make sel from name
|
|
strcpy(sname, "set");
|
|
strcat(sname, ckey);
|
|
strcat(sname, ":");
|
|
sname[3] = islower(sname[3]) ? toupper(sname[3]) : sname[3];
|
|
|
|
sel = sel_get_any_uid(sname);
|
|
|
|
if (sel && (mth = class_get_instance_method(class, sel))
|
|
&& method_get_number_of_arguments(mth) == 3
|
|
&& *objc_skip_type_qualifiers(mth->method_types) == _C_VOID)
|
|
{
|
|
char* argType = (char*)(mth->method_types);
|
|
|
|
argType = (char*)objc_skip_argspec(argType); // skip return
|
|
argType = (char*)objc_skip_argspec(argType); // skip self
|
|
argType = (char*)objc_skip_argspec(argType); // skip SEL
|
|
|
|
switch (*objc_skip_type_qualifiers(argType))
|
|
{
|
|
case _C_ID:
|
|
fptr = (void (*)(void*, void*, id, id))idMethodSetFunc;
|
|
idMethod = YES;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (void (*)(void*, void*, id, id))charMethodSetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (void (*)(void*, void*, id, id))intMethodSetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (void (*)(void*, void*, id, id))longMethodSetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info1 = (void*)(mth->method_imp);
|
|
info2 = (void*)(mth->method_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lookup ivar name
|
|
// NSDebugFLog(@"accessInstanceVariablesDirectly=%d",[NSObject accessInstanceVariablesDirectly]);
|
|
|
|
if (!fptr && [NSObject accessInstanceVariablesDirectly])
|
|
{
|
|
const char *ckey = [key cString];
|
|
int keyType=0;
|
|
|
|
for (keyType = 0; !fptr && keyType < 2; keyType++)
|
|
{
|
|
const char* testKey=ckey;
|
|
char* testKeyDup=NULL;
|
|
Class class = [instance class];
|
|
|
|
if (keyType==1)
|
|
{
|
|
int len=strlen(testKey);
|
|
testKeyDup=malloc(len+2);
|
|
testKeyDup[0]='_';
|
|
strcpy(testKeyDup+1,testKey);
|
|
testKey=testKeyDup;
|
|
}
|
|
|
|
// NSDebugFLog(@"testKey=%s",testKey);
|
|
|
|
while (!fptr && class)
|
|
{
|
|
int i;
|
|
|
|
// NSDebugFLog(@"class=%@",NSStringFromClass(class));
|
|
|
|
for (i = 0;
|
|
!fptr && class->ivars && i < class->ivars->ivar_count;
|
|
i++)
|
|
{
|
|
if (!strcmp(testKey, class->ivars->ivar_list[i].ivar_name))
|
|
{
|
|
// NSDebugFLog(@"Found");
|
|
|
|
switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type))
|
|
{
|
|
case _C_ID:
|
|
fptr = (void (*)(void*, void*, id, id))idIvarSetFunc;
|
|
idMethod = YES;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (void (*)(void*, void*, id, id))charIvarSetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (void (*)(void*, void*, id, id))intIvarSetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (void (*)(void*, void*, id, id))longIvarSetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc;
|
|
break;
|
|
}
|
|
if (fptr) {
|
|
info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
|
|
}
|
|
}
|
|
}
|
|
class = class->super_class;
|
|
}
|
|
|
|
if (testKeyDup)
|
|
{
|
|
free(testKeyDup);
|
|
testKeyDup = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// NSDebugFLog(@"fptr=%p",fptr);
|
|
|
|
if (fptr && !idMethod && value == nil)
|
|
return (SetKeyValueBinding *) - 1;
|
|
|
|
// Make binding and insert into map
|
|
|
|
if (fptr)
|
|
{
|
|
KeyValueMethod *mkey = NSZoneMalloc(NSDefaultMallocZone(), sizeof(KeyValueMethod));
|
|
SetKeyValueBinding *bin = NSZoneMalloc(NSDefaultMallocZone(), sizeof(SetKeyValueBinding));
|
|
|
|
mkey->key = [key copy];
|
|
mkey->class = [instance class];
|
|
|
|
bin->access = fptr;
|
|
bin->info1 = info1;
|
|
bin->info2 = info2;
|
|
|
|
NSMapInsert(setValueBindings, mkey, bin);
|
|
ret = bin;
|
|
}
|
|
// If no way to access value warn
|
|
if (!ret && keyValueDebug)
|
|
NSLog(@"cannnot set key `%@' for instance of class `%@'",
|
|
key, NSStringFromClass([instance class]));
|
|
|
|
return ret;
|
|
}
|
|
|
|
static SetKeyValueBinding *newSetStoredBinding(NSString *key, id instance, id value)
|
|
{
|
|
SetKeyValueBinding *ret = NULL;
|
|
void *info1 = NULL;
|
|
void *info2 = NULL;
|
|
void (*fptr)(void*, void*, id, id) = NULL;
|
|
BOOL idMethod = NO;
|
|
|
|
// Lookup ivar _name
|
|
{
|
|
Class class = [instance class];
|
|
const char* ckey = [key cString];
|
|
char iname[strlen(ckey) + 2];
|
|
int i;
|
|
|
|
// Make ivar from name
|
|
strcpy(iname, "_");
|
|
strcat(iname, ckey);
|
|
|
|
while (class)
|
|
{
|
|
for (i = 0; class->ivars && i < class->ivars->ivar_count; i++)
|
|
{
|
|
if (!strcmp(iname, class->ivars->ivar_list[i].ivar_name))
|
|
{
|
|
switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type))
|
|
{
|
|
case _C_ID:
|
|
fptr = (void (*)(void*, void*, id, id))idIvarSetFunc;
|
|
idMethod = YES;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (void (*)(void*, void*, id, id))charIvarSetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (void (*)(void*, void*, id, id))intIvarSetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (void (*)(void*, void*, id, id))longIvarSetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
class = class->super_class;
|
|
}
|
|
}
|
|
|
|
// Lookup method name [-(void)_setKey:(type)arg]
|
|
if (!fptr)
|
|
{
|
|
Class class = [instance class];
|
|
const char* ckey = [key cString];
|
|
SEL sel;
|
|
struct objc_method* mth;
|
|
char sname[strlen(ckey) + 7];
|
|
|
|
// Make sel from name
|
|
strcpy(sname, "_set");
|
|
strcat(sname, ckey);
|
|
strcat(sname, ":");
|
|
sname[3] = islower(sname[3]) ? toupper(sname[3]) : sname[3];
|
|
sel = sel_get_any_uid(sname);
|
|
|
|
if (sel && (mth = class_get_instance_method(class, sel))
|
|
&& method_get_number_of_arguments(mth) == 3
|
|
&& *objc_skip_type_qualifiers(mth->method_types) == _C_VOID)
|
|
{
|
|
char *argType = (char*)(mth->method_types);
|
|
|
|
argType = (char*)objc_skip_argspec(argType); // skip return
|
|
argType = (char*)objc_skip_argspec(argType); // skip self
|
|
argType = (char*)objc_skip_argspec(argType); // skip SEL
|
|
|
|
switch (*objc_skip_type_qualifiers(argType))
|
|
{
|
|
case _C_ID:
|
|
fptr = (void (*)(void*, void*, id, id))idMethodSetFunc;
|
|
idMethod = YES;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (void (*)(void*, void*, id, id))charMethodSetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (void (*)(void*, void*, id, id))intMethodSetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (void (*)(void*, void*, id, id))longMethodSetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info1 = (void*)(mth->method_imp);
|
|
info2 = (void*)(mth->method_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lookup ivar name
|
|
if (!fptr)
|
|
{
|
|
Class class = [instance class];
|
|
const char* ckey = [key cString];
|
|
int i;
|
|
|
|
while (class)
|
|
{
|
|
for (i = 0; class->ivars && i < class->ivars->ivar_count; i++)
|
|
{
|
|
if (!strcmp(ckey, class->ivars->ivar_list[i].ivar_name))
|
|
{
|
|
switch (*objc_skip_type_qualifiers(class->ivars->ivar_list[i].ivar_type))
|
|
{
|
|
case _C_ID:
|
|
fptr = (void (*)(void*, void*, id, id))idIvarSetFunc;
|
|
idMethod = YES;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (void (*)(void*, void*, id, id))charIvarSetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedCharIvarSetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (void (*)(void*, void*, id, id))shortIvarSetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedShortIvarSetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (void (*)(void*, void*, id, id))intIvarSetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedIntIvarSetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (void (*)(void*, void*, id, id))longIvarSetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongIvarSetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (void (*)(void*, void*, id, id))longLongIvarSetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongLongIvarSetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (void (*)(void*, void*, id, id))floatIvarSetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (void (*)(void*, void*, id, id))doubleIvarSetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info2 = (void*)(class->ivars->ivar_list[i].ivar_offset);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
class = class->super_class;
|
|
}
|
|
}
|
|
|
|
// Lookup method name [-(void)setKey:(type)arg]
|
|
if (!fptr)
|
|
{
|
|
Class class = [instance class];
|
|
const char* ckey = [key cString];
|
|
SEL sel;
|
|
struct objc_method* mth;
|
|
char sname[strlen(ckey) + 7];
|
|
|
|
// Make sel from name
|
|
strcpy(sname, "set");
|
|
strcat(sname, ckey);
|
|
strcat(sname, ":");
|
|
sname[3] = islower(sname[3]) ? toupper(sname[3]) : sname[3];
|
|
sel = sel_get_any_uid(sname);
|
|
|
|
if (sel && (mth = class_get_instance_method(class, sel))
|
|
&& method_get_number_of_arguments(mth) == 3
|
|
&& *objc_skip_type_qualifiers(mth->method_types) == _C_VOID)
|
|
{
|
|
char *argType = (char*)(mth->method_types);
|
|
|
|
argType = (char*)objc_skip_argspec(argType); // skip return
|
|
argType = (char*)objc_skip_argspec(argType); // skip self
|
|
argType = (char*)objc_skip_argspec(argType); // skip SEL
|
|
|
|
switch (*objc_skip_type_qualifiers(argType))
|
|
{
|
|
case _C_ID:
|
|
fptr = (void (*)(void*, void*, id, id))idMethodSetFunc;
|
|
idMethod = YES;
|
|
break;
|
|
case _C_CHR:
|
|
fptr = (void (*)(void*, void*, id, id))charMethodSetFunc;
|
|
break;
|
|
case _C_UCHR:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedCharMethodSetFunc;
|
|
break;
|
|
case _C_SHT:
|
|
fptr = (void (*)(void*, void*, id, id))shortMethodSetFunc;
|
|
break;
|
|
case _C_USHT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedShortMethodSetFunc;
|
|
break;
|
|
case _C_INT:
|
|
fptr = (void (*)(void*, void*, id, id))intMethodSetFunc;
|
|
break;
|
|
case _C_UINT:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedIntMethodSetFunc;
|
|
break;
|
|
case _C_LNG:
|
|
fptr = (void (*)(void*, void*, id, id))longMethodSetFunc;
|
|
break;
|
|
case _C_ULNG:
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongMethodSetFunc;
|
|
break;
|
|
case 'q':
|
|
fptr = (void (*)(void*, void*, id, id))longLongMethodSetFunc;
|
|
break;
|
|
case 'Q':
|
|
fptr = (void (*)(void*, void*, id, id))unsignedLongLongMethodSetFunc;
|
|
break;
|
|
case _C_FLT:
|
|
fptr = (void (*)(void*, void*, id, id))floatMethodSetFunc;
|
|
break;
|
|
case _C_DBL:
|
|
fptr = (void (*)(void*, void*, id, id))doubleMethodSetFunc;
|
|
break;
|
|
}
|
|
|
|
if (fptr)
|
|
{
|
|
info1 = (void*)(mth->method_imp);
|
|
info2 = (void*)(mth->method_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fptr && !idMethod && value == nil)
|
|
return (SetKeyValueBinding *)-1;
|
|
|
|
// Make binding and insert into map
|
|
if (fptr)
|
|
{
|
|
KeyValueMethod* mkey = NSZoneMalloc(NSDefaultMallocZone(), sizeof(KeyValueMethod));
|
|
SetKeyValueBinding* bin = NSZoneMalloc(NSDefaultMallocZone(), sizeof(SetKeyValueBinding));
|
|
|
|
mkey->key = [key copy];
|
|
mkey->class = [instance class];
|
|
|
|
bin->access = fptr;
|
|
bin->info1 = info1;
|
|
bin->info2 = info2;
|
|
|
|
NSMapInsert(setStoredValueBindings, mkey, bin);
|
|
ret = bin;
|
|
}
|
|
|
|
// If no way to access value warn
|
|
if (!ret && keyValueDebug)
|
|
NSLog(@"cannnot set key `%@' for instance of class `%@'",
|
|
key, NSStringFromClass([instance class]));
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* MapTable initialization
|
|
*/
|
|
|
|
static unsigned keyValueMapHash(NSMapTable *table, KeyValueMethod *map)
|
|
{
|
|
return [map->key hash] + (((int)(map->class)) >> 4);
|
|
}
|
|
|
|
static BOOL keyValueMapCompare(NSMapTable *table,
|
|
KeyValueMethod *map1, KeyValueMethod *map2)
|
|
{
|
|
return (map1->class == map2->class) && [map1->key isEqual: map2->key];
|
|
}
|
|
|
|
static void mapRetainNothing(NSMapTable *table, KeyValueMethod *map)
|
|
{
|
|
}
|
|
|
|
static void keyValueMapKeyRelease(NSMapTable *table, KeyValueMethod *map)
|
|
{
|
|
[map->key release];
|
|
NSZoneFree(NSDefaultMallocZone(), map);
|
|
}
|
|
|
|
static void keyValueMapValRelease(NSMapTable *table, void *map)
|
|
{
|
|
NSZoneFree(NSDefaultMallocZone(), map);
|
|
}
|
|
|
|
static NSString *keyValueMapDescribe(NSMapTable *table, KeyValueMethod *map)
|
|
{
|
|
return [NSString stringWithFormat: @"%@:%@",
|
|
NSStringFromClass(map->class), map->key];
|
|
}
|
|
|
|
static NSString *describeBinding(NSMapTable *table, GetKeyValueBinding *bin)
|
|
{
|
|
return [NSString stringWithFormat: @"%08x:%08x", bin->info1, bin->info2];
|
|
}
|
|
|
|
static NSMapTableKeyCallBacks keyValueKeyCallbacks =
|
|
{
|
|
(unsigned(*)(NSMapTable *, const void *))keyValueMapHash,
|
|
(BOOL(*)(NSMapTable *, const void *, const void *))keyValueMapCompare,
|
|
(void (*)(NSMapTable *, const void *anObject))mapRetainNothing,
|
|
(void (*)(NSMapTable *, void *anObject))keyValueMapKeyRelease,
|
|
(NSString *(*)(NSMapTable *, const void *))keyValueMapDescribe,
|
|
(const void *)NULL
|
|
};
|
|
|
|
const NSMapTableValueCallBacks keyValueValueCallbacks =
|
|
{
|
|
(void (*)(NSMapTable *, const void *))mapRetainNothing,
|
|
(void (*)(NSMapTable *, void *))keyValueMapValRelease,
|
|
(NSString *(*)(NSMapTable *, const void *))describeBinding
|
|
};
|
|
|
|
static void initKeyValueBindings(void)
|
|
{
|
|
getValueBindings = NSCreateMapTable(keyValueKeyCallbacks,
|
|
keyValueValueCallbacks, 31);
|
|
setValueBindings = NSCreateMapTable(keyValueKeyCallbacks,
|
|
keyValueValueCallbacks, 31);
|
|
getStoredValueBindings = NSCreateMapTable(keyValueKeyCallbacks,
|
|
keyValueValueCallbacks, 31);
|
|
setStoredValueBindings = NSCreateMapTable(keyValueKeyCallbacks,
|
|
keyValueValueCallbacks, 31);
|
|
keyValueInit = YES;
|
|
}
|
|
|
|
/*
|
|
* Access Methods
|
|
*/
|
|
|
|
static inline void removeAllBindings(void)
|
|
{
|
|
NSResetMapTable(getValueBindings);
|
|
NSResetMapTable(setValueBindings);
|
|
NSResetMapTable(getStoredValueBindings);
|
|
NSResetMapTable(setStoredValueBindings);
|
|
}
|
|
|
|
static inline id getValue(NSString *key, id instance, BOOL *found)
|
|
{
|
|
KeyValueMethod mkey = {key, [instance class]};
|
|
GetKeyValueBinding *bin;
|
|
id value = nil;
|
|
|
|
// Check Init
|
|
if (!keyValueInit)
|
|
initKeyValueBindings();
|
|
|
|
// NSDebugFLog(@"after init");
|
|
// Get existing binding
|
|
bin = (GetKeyValueBinding *)NSMapGet(getValueBindings, &mkey);
|
|
|
|
// Create new binding
|
|
if (!bin)
|
|
bin = newGetBinding(key, instance);
|
|
|
|
// Get value if binding is ok
|
|
if (bin)
|
|
{
|
|
// NSDebugFLog(@"bin->");
|
|
value = bin->access(bin->info1, bin->info2, instance);
|
|
// NSDebugFLog(@"after bin->");
|
|
*found = YES;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static inline id getStoredValue(NSString *key, id instance, BOOL *found)
|
|
{
|
|
KeyValueMethod mkey = {key, [instance class]};
|
|
GetKeyValueBinding *bin;
|
|
id value = nil;
|
|
|
|
// Check Init
|
|
if (!keyValueInit)
|
|
initKeyValueBindings();
|
|
|
|
// Get existing binding
|
|
bin = (GetKeyValueBinding *)NSMapGet(getStoredValueBindings, &mkey);
|
|
|
|
// Create new binding
|
|
if (!bin)
|
|
bin = newGetStoredBinding(key, instance);
|
|
|
|
// Get value if binding is ok
|
|
if (bin)
|
|
{
|
|
value = bin->access(bin->info1, bin->info2, instance);
|
|
*found = YES;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static inline BOOL setValue(NSString *key, id instance, id value)
|
|
{
|
|
KeyValueMethod mkey = {key, [instance class]};
|
|
SetKeyValueBinding *bin;
|
|
|
|
// Check Init
|
|
if(!keyValueInit)
|
|
initKeyValueBindings();
|
|
|
|
// Get existing binding
|
|
bin = (SetKeyValueBinding *)NSMapGet(setValueBindings, &mkey);
|
|
|
|
// Create new binding
|
|
if (!bin)
|
|
bin = newSetBinding(key, instance, value);
|
|
|
|
if (bin == (SetKeyValueBinding *)-1)
|
|
{
|
|
[instance unableToSetNilForKey:key];
|
|
return YES;
|
|
}
|
|
|
|
// Get value if binding is ok
|
|
if (bin)
|
|
bin->access(bin->info1, bin->info2, instance, value);
|
|
|
|
return (bin != NULL);
|
|
}
|
|
|
|
static inline BOOL setStoredValue(NSString *key, id instance, id value)
|
|
{
|
|
KeyValueMethod mkey = {key, [instance class]};
|
|
SetKeyValueBinding *bin;
|
|
|
|
// Check Init
|
|
if (!keyValueInit)
|
|
initKeyValueBindings();
|
|
|
|
// Get existing binding
|
|
bin = (SetKeyValueBinding *)NSMapGet(setStoredValueBindings, &mkey);
|
|
|
|
// Create new binding
|
|
if (!bin)
|
|
bin = newSetStoredBinding(key, instance, value);
|
|
|
|
if (bin == (SetKeyValueBinding *) - 1)
|
|
{
|
|
[instance unableToSetNilForKey: key];
|
|
return YES;
|
|
}
|
|
|
|
// Get value if binding is ok
|
|
if(bin)
|
|
bin->access(bin->info1, bin->info2, instance, value);
|
|
|
|
return (bin != NULL);
|
|
}
|
|
|
|
/*
|
|
* Methods
|
|
*/
|
|
|
|
- (void)setKeyValueCodingWarnings: (BOOL)aFlag //REMOVE
|
|
{
|
|
keyValueDebug = aFlag;
|
|
}
|
|
|
|
- (id)valueForKeyPath: (NSString *)key
|
|
{
|
|
NSArray *pathArray = [key componentsSeparatedByString: @"."];
|
|
NSEnumerator *pathEnum;
|
|
NSString *path;
|
|
id obj = self;
|
|
|
|
pathEnum = [pathArray objectEnumerator];
|
|
while ((path = [pathEnum nextObject]))
|
|
{
|
|
obj = [obj valueForKey: path];
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
- (void)takeValue: value forKeyPath: (NSString *)key
|
|
{
|
|
NSArray *pathArray = [key componentsSeparatedByString: @"."];
|
|
NSString *path;
|
|
id obj = self;
|
|
int i, count;
|
|
|
|
count = [pathArray count];
|
|
|
|
for (i = 0; i < (count - 1); i++)
|
|
{
|
|
path = [pathArray objectAtIndex: i];
|
|
obj = [obj valueForKey: path];
|
|
}
|
|
|
|
path = [pathArray lastObject];
|
|
[obj takeValue: value forKey: path];
|
|
}
|
|
|
|
- (NSDictionary *)valuesForKeys: (NSArray *)keys
|
|
{
|
|
int i, n = [keys count];
|
|
NSMutableArray *newKeys = [[[NSMutableArray alloc] initWithCapacity: n]
|
|
autorelease];
|
|
NSMutableArray *newVals = [[[NSMutableArray alloc] initWithCapacity: n]
|
|
autorelease];
|
|
EONull *null = [EONull null];
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
id key = [keys objectAtIndex: i];
|
|
id val = [self valueForKey: key];
|
|
|
|
if (val == nil)
|
|
val = null;
|
|
|
|
[newKeys addObject: key];
|
|
[newVals addObject: val];
|
|
}
|
|
|
|
return [NSDictionary dictionaryWithObjects: newVals forKeys: newKeys];
|
|
}
|
|
|
|
- (void)takeValuesFromDictionary: (NSDictionary *)dictionary
|
|
{
|
|
NSEnumerator *keyEnum = [dictionary keyEnumerator];
|
|
id key;
|
|
id val;
|
|
|
|
while ((key = [keyEnum nextObject]))
|
|
{
|
|
val = [dictionary objectForKey: key];
|
|
|
|
if ([val isKindOfClass: [[EONull null] class]])
|
|
val = nil;
|
|
|
|
[self takeValue: val forKey: key];
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
// Implemented in NSObject
|
|
@implementation NSObject (EOKeyValueCodingPrimitives)
|
|
|
|
- (id)valueForKey: (NSString *)key
|
|
{
|
|
BOOL found = NO;
|
|
id val = nil;
|
|
|
|
// NSDebugFLog(@"valueForKey:");
|
|
|
|
val = getValue(key, self, &found);
|
|
|
|
if (found == NO)
|
|
val = [self handleQueryWithUnboundKey: key];
|
|
|
|
return val;
|
|
}
|
|
|
|
- (void)takeValue: (id)value
|
|
forKey: (NSString *)key
|
|
{
|
|
if (!setValue(key, self, value))
|
|
[self handleTakeValue: value forUnboundKey: key];
|
|
}
|
|
|
|
- (id)storedValueForKey: (NSString *)key
|
|
{
|
|
BOOL found = NO;
|
|
id val = getStoredValue(key, self, &found);
|
|
|
|
if (found == NO)
|
|
val = [self handleQueryWithUnboundKey: key];
|
|
|
|
return val;
|
|
}
|
|
|
|
- (void)takeStoredValue: (id)value forKey: (NSString *)key
|
|
{
|
|
if (!setStoredValue(key, self, value))
|
|
[self handleTakeValue: value forUnboundKey: key];
|
|
}
|
|
|
|
+ (BOOL)accessInstanceVariablesDirectly
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
+ (BOOL)useStoredAccessor
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation NSObject (EOKeyValueCodingCacheControl)
|
|
|
|
+ (void)flushAllKeyBindings
|
|
{
|
|
removeAllBindings();
|
|
}
|
|
|
|
+ (void)flushClassKeyBindings
|
|
{
|
|
removeAllBindings();
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
/*
|
|
* EOKeyValueCodingException raises an exception by default
|
|
*/
|
|
|
|
@implementation NSObject (EOKeyValueCodingException)
|
|
|
|
- (id)handleQueryWithUnboundKey: (NSString *)key
|
|
{
|
|
NSString *reason=nil;
|
|
|
|
reason = [NSString stringWithFormat: @"%@ -- %@ 0x%x: cannot find value for key \"%@\"",
|
|
NSStringFromSelector(_cmd),
|
|
NSStringFromClass([self class]),
|
|
self,
|
|
key];
|
|
|
|
[[NSException exceptionWithName: EOUnknownKeyException
|
|
reason: reason
|
|
userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
|
|
self, EOTargetObjectUserInfoKey,
|
|
key, EOUnknownUserInfoKey,
|
|
nil]] raise];
|
|
return nil;
|
|
}
|
|
|
|
- (void)handleTakeValue: (id)value
|
|
forUnboundKey: (NSString *)key
|
|
{
|
|
NSString *reason=nil;
|
|
|
|
reason = [NSString stringWithFormat: @"%@ -- %@ 0x%x: cannot set value \"%@\" for key \"%@\"",
|
|
NSStringFromSelector(_cmd),
|
|
NSStringFromClass([self class]),
|
|
self,
|
|
value,
|
|
key];
|
|
|
|
[[NSException exceptionWithName: EOUnknownKeyException
|
|
reason: reason
|
|
userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
|
|
self, EOTargetObjectUserInfoKey,
|
|
key, EOUnknownUserInfoKey,
|
|
nil]] raise];
|
|
}
|
|
|
|
- (void)unableToSetNilForKey: (NSString *)key
|
|
{
|
|
[NSException raise: NSInvalidArgumentException
|
|
format: @"%@ -- %@ 0x%x: cannot set EONull value for key \"%@\"",
|
|
NSStringFromSelector(_cmd),
|
|
NSStringFromClass([self class]),
|
|
self,
|
|
key];
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
#endif
|