From 80c8891b1f73f1facf11fade6195b99a52a84730 Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Mon, 25 Feb 2002 07:05:58 +0000 Subject: [PATCH] Tidy key value coding git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@12742 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 4 + Headers/gnustep/base/NSKeyValueCoding.h | 2 +- Source/GNUmakefile | 1 + Source/NSKeyValueCoding.m | 430 ++++++++++++++++++++++++ Source/NSObject.m | 391 --------------------- 5 files changed, 436 insertions(+), 392 deletions(-) create mode 100644 Source/NSKeyValueCoding.m diff --git a/ChangeLog b/ChangeLog index 5e37ad600..3bf74260b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,10 @@ internals in scalar types and NSNumbers etc to NSObjCRuntime.m. Re-implemented path methods to fix incorrect implementation as pointed out by Manuel Guesdon. + * Headers/Foundation/NSObjCRuntime.h: New functions from NSObject + * Source/NSObjCRuntime.m: New functions from NSObject + * Source/NSKeyValueCoding.m: Put key value coding methods here for + clarity and ease of documentation. 2002-02-24 Richard Frith-Macdonald diff --git a/Headers/gnustep/base/NSKeyValueCoding.h b/Headers/gnustep/base/NSKeyValueCoding.h index 6ae2ebec9..96cecdac3 100644 --- a/Headers/gnustep/base/NSKeyValueCoding.h +++ b/Headers/gnustep/base/NSKeyValueCoding.h @@ -1,5 +1,5 @@ -/* Interface for NSKeyvalueCoding for GNUStep +/* Interface for NSKeyValueCoding for GNUStep Copyright (C) 2000 Free Software Foundation, Inc. Written by: Richard Frith-Macdonald diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 4c67dab87..c233772e7 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -190,6 +190,7 @@ NSGeometry.m \ NSHashTable.m \ NSHost.m \ NSInvocation.m \ +NSKeyValueCoding.m \ NSLock.m \ NSLog.m \ NSMapTable.m \ diff --git a/Source/NSKeyValueCoding.m b/Source/NSKeyValueCoding.m new file mode 100644 index 000000000..850e5a281 --- /dev/null +++ b/Source/NSKeyValueCoding.m @@ -0,0 +1,430 @@ +/** Implementation of KeyValueCoding for GNUStep + Copyright (C) 2000,2002 Free Software Foundation, Inc. + + Written by: Richard Frith-Macdonald + + This file is part of the GNUstep Base Library. + + 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 2 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; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + + NSKeyValueCoding informal protocol reference + $Date$ $Revision$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + * This describes an informal protocol for key-value coding. + * The basic methods are implemented as a category of the NSObject class, + * but other classes override those default implementations to perform + * more specific operations. + */ +@implementation NSObject (KeyValueCoding) + ++ (BOOL) accessInstanceVariablesDirectly +{ + return YES; +} + ++ (BOOL) useStoredAccessor +{ + return YES; +} + +- (id) handleQueryWithUnboundKey: (NSString*)aKey +{ + [NSException raise: NSGenericException + format: @"%@ -- %@ 0x%x: Unable to find value for key \"%@\"", + NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, aKey]; + + return nil; +} + +- (void) handleTakeValue: (id)anObject forUnboundKey: (NSString*)aKey +{ + [NSException raise: NSGenericException + format: @"%@ -- %@ 0x%x: Unable set value \"%@\" for key \"%@\"", + NSStringFromSelector(_cmd), NSStringFromClass([self class]), + self, anObject, aKey]; +} + +- (id) storedValueForKey: (NSString*)aKey +{ + unsigned size; + + if ([[self class] useStoredAccessor] == NO) + { + return [self valueForKey: aKey]; + } + + size = [aKey cStringLength]; + if (size < 1) + { + [NSException raise: NSInvalidArgumentException + format: @"storedValueForKey: ... empty key"]; + return NO; // avoid compiler warnings. + } + else + { + SEL sel = 0; + const char *type = NULL; + unsigned off; + const char *name; + char buf[size+5]; + char lo; + char hi; + + strcpy(buf, "_get"); + [aKey getCString: &buf[4]]; + lo = buf[4]; + hi = islower(lo) ? toupper(lo) : lo; + buf[4] = hi; + + name = buf; // _getKey + sel = sel_get_any_uid(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + buf[3] = '_'; + buf[4] = lo; + name = &buf[3]; // _key + sel = sel_get_any_uid(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + } + } + if (sel == 0) + { + if ([[self class] accessInstanceVariablesDirectly] == YES) + { + // _key + if (GSFindInstanceVariable(self, name, &type, &size, &off) == NO) + { + name = &buf[4]; // key + GSFindInstanceVariable(self, name, &type, &size, &off); + } + } + if (type == NULL) + { + buf[3] = 't'; + buf[4] = hi; + name = &buf[1]; // getKey + sel = sel_get_any_uid(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + buf[4] = lo; + name = &buf[4]; // key + sel = sel_get_any_uid(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + } + } + } + } + return GSGetValue(self, aKey, sel, type, size, off); + } +} + +- (void) takeStoredValue: (id)anObject forKey: (NSString*)aKey +{ + unsigned size; + + if ([[self class] useStoredAccessor] == NO) + { + [self takeValue: anObject forKey: aKey]; + return; + } + + size = [aKey length]; + if (size < 1) + { + [NSException raise: NSInvalidArgumentException + format: @"takeStoredValue:forKey: ... empty key"]; + } + else + { + SEL sel; + const char *type; + int off; + const char *name; + char buf[size+6]; + char lo; + char hi; + + strcpy(buf, "_set"); + [aKey getCString: &buf[4]]; + lo = buf[4]; + hi = islower(lo) ? toupper(lo) : lo; + buf[4] = hi; + buf[size+4] = ':'; + + name = buf; // _setKey: + type = NULL; + sel = GSSelectorFromName(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + if ([[self class] accessInstanceVariablesDirectly] == YES) + { + buf[size+4] = '\0'; + buf[4] = lo; + buf[3] = '_'; + name = &buf[3]; // _key + if (GSFindInstanceVariable(self, name, &type, &size, &off) == NO) + { + name = &buf[4]; // key + GSFindInstanceVariable(self, name, &type, &size, &off); + } + } + if (type == NULL) + { + buf[size+4] = ':'; + buf[4] = hi; + buf[3] = 't'; + name = &buf[1]; // setKey: + sel = GSSelectorFromName(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + } + } + } + GSSetValue(self, aKey, anObject, sel, type, size, off); + } +} + +- (void) takeValue: (id)anObject forKey: (NSString*)aKey +{ + unsigned size; + + size = [aKey length]; + if (size < 1) + { + [NSException raise: NSInvalidArgumentException + format: @"takeValue:forKey: ... empty key"]; + } + else + { + SEL sel; + const char *type; + int off; + const char *name; + char buf[size+6]; + char lo; + char hi; + + strcpy(buf, "_set"); + [aKey getCString: &buf[4]]; + lo = buf[4]; + hi = islower(lo) ? toupper(lo) : lo; + buf[4] = hi; + buf[size+4] = ':'; + + name = &buf[1]; // setKey: + type = NULL; + sel = GSSelectorFromName(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + name = buf; // _setKey: + sel = GSSelectorFromName(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + if ([[self class] accessInstanceVariablesDirectly] == YES) + { + buf[size+4] = '\0'; + buf[3] = '_'; + buf[4] = lo; + name = &buf[3]; // _key + if (GSFindInstanceVariable(self, name, &type, &size, &off) + == NO) + { + name = &buf[4]; // key + GSFindInstanceVariable(self, name, &type, &size, &off); + } + } + } + } + GSSetValue(self, aKey, anObject, sel, type, size, off); + } +} + +- (void) takeValue: (id)anObject forKeyPath: (NSString*)aKey +{ + NSRange r = [aKey rangeOfString: @"."]; + + if (r.length == 0) + { + [self takeValue: anObject forKey: aKey]; + } + else + { + NSString *key = [aKey substringToIndex: r.location]; + NSString *path = [aKey substringFromIndex: NSMaxRange(r)]; + + [[self valueForKey: key] takeValue: anObject forKeyPath: path]; + } +} + +- (void) takeValuesFromDictionary: (NSDictionary*)aDictionary +{ + NSEnumerator *enumerator = [aDictionary keyEnumerator]; + NSNull *null = [NSNull null]; + NSString *key; + + while ((key = [enumerator nextObject]) != nil) + { + id obj = [aDictionary objectForKey: key]; + + if (obj == null) + { + obj = nil; + } + [self takeValue: obj forKey: key]; + } +} + +- (void) unableToSetNilForKey: (NSString*)aKey +{ + [NSException raise: NSInvalidArgumentException + format: @"%@ -- %@ 0x%x: Given nil value to set for key \"%@\"", + NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, aKey]; +} + +- (id) valueForKey: (NSString*)aKey +{ + unsigned size; + + size = [aKey length]; + if (size < 1) + { + [NSException raise: NSInvalidArgumentException + format: @"valueForKey: ... empty key"]; + return nil; + } + else + { + SEL sel = 0; + const char *type = NULL; + unsigned off; + const char *name; + char buf[size+5]; + char lo; + char hi; + + strcpy(buf, "_get"); + [aKey getCString: &buf[4]]; + lo = buf[4]; + hi = islower(lo) ? toupper(lo) : lo; + buf[4] = hi; + + name = &buf[1]; // getKey + sel = GSSelectorFromName(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + buf[4] = lo; + name = &buf[4]; // key + sel = GSSelectorFromName(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + buf[4] = hi; + name = buf; // _getKey + sel = GSSelectorFromName(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + buf[4] = lo; + buf[3] = '_'; + name = &buf[3]; // _key + sel = GSSelectorFromName(name); + if (sel == 0 || [self respondsToSelector: sel] == NO) + { + sel = 0; + } + } + } + } + + if (sel == 0 && [[self class] accessInstanceVariablesDirectly] == YES) + { + buf[4] = lo; + buf[3] = '_'; + name = &buf[3]; // _key + if (GSFindInstanceVariable(self, name, &type, &size, &off) == NO) + { + name = &buf[4]; // key + GSFindInstanceVariable(self, name, &type, &size, &off); + } + } + return GSGetValue(self, aKey, sel, type, size, off); + } +} + +- (id) valueForKeyPath: (NSString*)aKey +{ + NSRange r = [aKey rangeOfString: @"."]; + id o; + + if (r.length == 0) + { + o = [self valueForKey: aKey]; + } + else + { + NSString *key = [aKey substringToIndex: r.location]; + NSString *path = [aKey substringFromIndex: NSMaxRange(r)]; + + o = [[self valueForKey: key] valueForKeyPath: path]; + } + return o; +} + +- (NSDictionary*) valuesForKeys: (NSArray*)keys +{ + NSMutableDictionary *dict; + NSNull *null = [NSNull null]; + unsigned count = [keys count]; + unsigned pos; + + dict = [NSMutableDictionary dictionaryWithCapacity: count]; + for (pos = 0; pos < count; pos++) + { + NSString *key = [keys objectAtIndex: pos]; + id val = [self valueForKey: key]; + + if (val == nil) + { + val = null; + } + [dict setObject: val forKey: key]; + } + return AUTORELEASE([dict copy]); +} + +@end + diff --git a/Source/NSObject.m b/Source/NSObject.m index 42219d9d9..798d2620c 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -1280,397 +1280,6 @@ static BOOL double_release_check_enabled = NO; -#include -#include -#include - - -@implementation NSObject (KeyValueCoding) - -+ (BOOL) accessInstanceVariablesDirectly -{ - return YES; -} - -+ (BOOL) useStoredAccessor -{ - return YES; -} - -- (id) handleQueryWithUnboundKey: (NSString*)aKey -{ - [NSException raise: NSGenericException - format: @"%@ -- %@ 0x%x: Unable to find value for key \"%@\"", - NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, aKey]; - - return nil; -} - -- (void) handleTakeValue: (id)anObject forUnboundKey: (NSString*)aKey -{ - [NSException raise: NSGenericException - format: @"%@ -- %@ 0x%x: Unable set value \"%@\" for key \"%@\"", - NSStringFromSelector(_cmd), NSStringFromClass([self class]), - self, anObject, aKey]; -} - -- (id) storedValueForKey: (NSString*)aKey -{ - unsigned size; - - if ([[self class] useStoredAccessor] == NO) - { - return [self valueForKey: aKey]; - } - - size = [aKey cStringLength]; - if (size < 1) - { - [NSException raise: NSInvalidArgumentException - format: @"storedValueForKey: ... empty key"]; - return NO; // avoid compiler warnings. - } - else - { - SEL sel = 0; - const char *type = NULL; - unsigned off; - const char *name; - char buf[size+5]; - char lo; - char hi; - - strcpy(buf, "_get"); - [aKey getCString: &buf[4]]; - lo = buf[4]; - hi = islower(lo) ? toupper(lo) : lo; - buf[4] = hi; - - name = buf; // _getKey - sel = sel_get_any_uid(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - buf[3] = '_'; - buf[4] = lo; - name = &buf[3]; // _key - sel = sel_get_any_uid(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - sel = 0; - } - } - if (sel == 0) - { - if ([[self class] accessInstanceVariablesDirectly] == YES) - { - // _key - if (GSFindInstanceVariable(self, name, &type, &size, &off) == NO) - { - name = &buf[4]; // key - GSFindInstanceVariable(self, name, &type, &size, &off); - } - } - if (type == NULL) - { - buf[3] = 't'; - buf[4] = hi; - name = &buf[1]; // getKey - sel = sel_get_any_uid(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - buf[4] = lo; - name = &buf[4]; // key - sel = sel_get_any_uid(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - sel = 0; - } - } - } - } - return GSGetValue(self, aKey, sel, type, size, off); - } -} - -- (void) takeStoredValue: (id)anObject forKey: (NSString*)aKey -{ - unsigned size; - - if ([[self class] useStoredAccessor] == NO) - { - [self takeValue: anObject forKey: aKey]; - return; - } - - size = [aKey length]; - if (size < 1) - { - [NSException raise: NSInvalidArgumentException - format: @"takeStoredValue:forKey: ... empty key"]; - } - else - { - SEL sel; - const char *type; - int off; - const char *name; - char buf[size+6]; - char lo; - char hi; - - strcpy(buf, "_set"); - [aKey getCString: &buf[4]]; - lo = buf[4]; - hi = islower(lo) ? toupper(lo) : lo; - buf[4] = hi; - buf[size+4] = ':'; - - name = buf; // _setKey: - type = NULL; - sel = GSSelectorFromName(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - sel = 0; - if ([[self class] accessInstanceVariablesDirectly] == YES) - { - buf[size+4] = '\0'; - buf[4] = lo; - buf[3] = '_'; - name = &buf[3]; // _key - if (GSFindInstanceVariable(self, name, &type, &size, &off) == NO) - { - name = &buf[4]; // key - GSFindInstanceVariable(self, name, &type, &size, &off); - } - } - if (type == NULL) - { - buf[size+4] = ':'; - buf[4] = hi; - buf[3] = 't'; - name = &buf[1]; // setKey: - sel = GSSelectorFromName(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - sel = 0; - } - } - } - GSSetValue(self, aKey, anObject, sel, type, size, off); - } -} - -- (void) takeValue: (id)anObject forKey: (NSString*)aKey -{ - unsigned size; - - size = [aKey length]; - if (size < 1) - { - [NSException raise: NSInvalidArgumentException - format: @"takeValue:forKey: ... empty key"]; - } - else - { - SEL sel; - const char *type; - int off; - const char *name; - char buf[size+6]; - char lo; - char hi; - - strcpy(buf, "_set"); - [aKey getCString: &buf[4]]; - lo = buf[4]; - hi = islower(lo) ? toupper(lo) : lo; - buf[4] = hi; - buf[size+4] = ':'; - - name = &buf[1]; // setKey: - type = NULL; - sel = GSSelectorFromName(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - name = buf; // _setKey: - sel = GSSelectorFromName(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - sel = 0; - if ([[self class] accessInstanceVariablesDirectly] == YES) - { - buf[size+4] = '\0'; - buf[3] = '_'; - buf[4] = lo; - name = &buf[3]; // _key - if (GSFindInstanceVariable(self, name, &type, &size, &off) - == NO) - { - name = &buf[4]; // key - GSFindInstanceVariable(self, name, &type, &size, &off); - } - } - } - } - GSSetValue(self, aKey, anObject, sel, type, size, off); - } -} - -- (void) takeValue: (id)anObject forKeyPath: (NSString*)aKey -{ - NSRange r = [aKey rangeOfString: @"."]; - - if (r.length == 0) - { - [self takeValue: anObject forKey: aKey]; - } - else - { - NSString *key = [aKey substringToIndex: r.location]; - NSString *path = [aKey substringFromIndex: NSMaxRange(r)]; - - [[self valueForKey: key] takeValue: anObject forKeyPath: path]; - } -} - -- (void) takeValuesFromDictionary: (NSDictionary*)aDictionary -{ - NSEnumerator *enumerator = [aDictionary keyEnumerator]; - NSNull *null = [NSNull null]; - NSString *key; - - while ((key = [enumerator nextObject]) != nil) - { - id obj = [aDictionary objectForKey: key]; - - if (obj == null) - { - obj = nil; - } - [self takeValue: obj forKey: key]; - } -} - -- (void) unableToSetNilForKey: (NSString*)aKey -{ - [NSException raise: NSInvalidArgumentException - format: @"%@ -- %@ 0x%x: Given nil value to set for key \"%@\"", - NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, aKey]; -} - -- (id) valueForKey: (NSString*)aKey -{ - unsigned size; - - size = [aKey length]; - if (size < 1) - { - [NSException raise: NSInvalidArgumentException - format: @"valueForKey: ... empty key"]; - return nil; - } - else - { - SEL sel = 0; - const char *type = NULL; - unsigned off; - const char *name; - char buf[size+5]; - char lo; - char hi; - - strcpy(buf, "_get"); - [aKey getCString: &buf[4]]; - lo = buf[4]; - hi = islower(lo) ? toupper(lo) : lo; - buf[4] = hi; - - name = &buf[1]; // getKey - sel = GSSelectorFromName(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - buf[4] = lo; - name = &buf[4]; // key - sel = GSSelectorFromName(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - buf[4] = hi; - name = buf; // _getKey - sel = GSSelectorFromName(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - buf[4] = lo; - buf[3] = '_'; - name = &buf[3]; // _key - sel = GSSelectorFromName(name); - if (sel == 0 || [self respondsToSelector: sel] == NO) - { - sel = 0; - } - } - } - } - - if (sel == 0 && [[self class] accessInstanceVariablesDirectly] == YES) - { - buf[4] = lo; - buf[3] = '_'; - name = &buf[3]; // _key - if (GSFindInstanceVariable(self, name, &type, &size, &off) == NO) - { - name = &buf[4]; // key - GSFindInstanceVariable(self, name, &type, &size, &off); - } - } - return GSGetValue(self, aKey, sel, type, size, off); - } -} - -- (id) valueForKeyPath: (NSString*)aKey -{ - NSRange r = [aKey rangeOfString: @"."]; - id o; - - if (r.length == 0) - { - o = [self valueForKey: aKey]; - } - else - { - NSString *key = [aKey substringToIndex: r.location]; - NSString *path = [aKey substringFromIndex: NSMaxRange(r)]; - - o = [[self valueForKey: key] valueForKeyPath: path]; - } - return o; -} - -- (NSDictionary*) valuesForKeys: (NSArray*)keys -{ - NSMutableDictionary *dict; - NSNull *null = [NSNull null]; - unsigned count = [keys count]; - unsigned pos; - - dict = [NSMutableDictionary dictionaryWithCapacity: count]; - for (pos = 0; pos < count; pos++) - { - NSString *key = [keys objectAtIndex: pos]; - id val = [self valueForKey: key]; - - if (val == nil) - { - val = null; - } - [dict setObject: val forKey: key]; - } - return AUTORELEASE([dict copy]); -} - -@end - - - @implementation NSObject (GNU) /* GNU Object class compatibility */