gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: GDL2/KVC...


From: David Ayers
Subject: Re: GDL2/KVC...
Date: Fri, 21 Mar 2003 23:28:36 +0100
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3b) Gecko/20030210

Manuel Guesdon wrote:

Seems last modifications have really broken GDL2. Before updating, I has a working version of GDL2+GNUstepWeb+GNUstep. After I get core dumps, exceptions,...

This happend to me too, and thats when I started reimplementing KVC.

I've commited my changes and tried to revert EOGenericRecord.m to a working version. I've fixed some other broken things (loops in EOEntity/EORelationship descriptions, loops in EOFault
forwardInvocation,..).

Could it be possible that before commiting changes, we make enought test in debug mode to try not to break (too much) things ?
I agree, and I'll try to have the guile tests in by Monday evening at the latest. But, since you are currently testing and have extra time, could you please have a look at my WIP... (I would like finish before the official RFA though.)

* EODefines.h: Added to coordinate exporting of functions.
* EONSAddOns.h/.m: Added GSUseStrictWO451Compatibility() function (and utility class for locks)
* EOKeyValueCoding.h/.m: Rewrite.

Cheers,
Dave



Index: dev-libs/gdl2/EOControl/GNUmakefile
===================================================================
RCS file: /cvsroot/gnustep/gnustep/dev-libs/gdl2/EOControl/GNUmakefile,v
retrieving revision 1.4
diff -u -r1.4 GNUmakefile
--- dev-libs/gdl2/EOControl/GNUmakefile 21 Mar 2003 20:41:07 -0000      1.4
+++ dev-libs/gdl2/EOControl/GNUmakefile 21 Mar 2003 22:17:41 -0000
@@ -95,8 +95,9 @@
 EODetailDataSource.h \
 EOUndoManager.h \
 EODebug.h \
-EOControl.h \
 EONSAddOns.h \
+EOControl.h \
+EODefines.h \
 
 
 gdl2control_AUTOGSDOC_HEADERS = $(libgnustep-db2control_HEADER_FILES)
Index: dev-libs/gdl2/EOControl/EODefines.h
===================================================================
RCS file: dev-libs/gdl2/EOControl/EODefines.h
diff -N dev-libs/gdl2/EOControl/EODefines.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dev-libs/gdl2/EOControl/EODefines.h 21 Mar 2003 22:17:41 -0000
@@ -0,0 +1,46 @@
+/* 
+   EODefines.h
+
+   Copyright (C) 2003 Free Software Foundation, Inc.
+
+   Author: David Ayers <address@hidden>
+   Date: March 2003
+
+   This file is part of the GNUstep Database 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; see the file COPYING.LIB.
+   If not, write to the Free Software Foundation,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __EOControl_EODefines_h__
+#define __EOControl_EODefines_h__
+
+#ifdef GNUSTEP_WITH_DLL
+
+#if BUILD_libgnustep_db2control_DLL
+#  define GDL2CONTROL_EXPORT  __declspec(dllexport)
+#else
+#  define GDL2CONTROL_EXPORT  extern __declspec(dllimport)
+#endif
+
+#else /* GNUSTEP_WITH[OUT]_DLL */
+
+#  define GDL2CONTROL_EXPORT extern
+
+#endif
+
+
+#endif /* __EOControl_EODefines_h__ */
+
Index: dev-libs/gdl2/EOControl/EONSAddOns.h
===================================================================
RCS file: /cvsroot/gnustep/gnustep/dev-libs/gdl2/EOControl/EONSAddOns.h,v
retrieving revision 1.2
diff -u -r1.2 EONSAddOns.h
--- dev-libs/gdl2/EOControl/EONSAddOns.h        30 Dec 2002 22:10:32 -0000      
1.2
+++ dev-libs/gdl2/EOControl/EONSAddOns.h        21 Mar 2003 22:17:41 -0000
@@ -30,8 +30,14 @@
 #import <Foundation/NSObject.h>
 #import <Foundation/NSString.h>
 
+#import <EOControl/EODefines.h>
 
 @class NSArray;
address@hidden NSLock;
address@hidden NSRecursiveLock;
+
+GDL2CONTROL_EXPORT BOOL
+GSUseStrictWO451Compatibility(NSString *key);
 
 
 @interface NSObject (NSObjectPerformingSelector)
@@ -73,6 +79,11 @@
 
 @interface NSString (YorYes)
 - (BOOL)isYorYES;
address@hidden
+
address@hidden GDL2GlobalLockVendor : NSObject
++ (NSLock *)globalLock;
++ (NSRecursiveLock *)globalRecursiveLock;
 @end
 
 
Index: dev-libs/gdl2/EOControl/EONSAddOns.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/dev-libs/gdl2/EOControl/EONSAddOns.m,v
retrieving revision 1.4
diff -u -r1.4 EONSAddOns.m
--- dev-libs/gdl2/EOControl/EONSAddOns.m        4 Feb 2003 15:16:58 -0000       
1.4
+++ dev-libs/gdl2/EOControl/EONSAddOns.m        21 Mar 2003 22:17:41 -0000
@@ -35,11 +35,45 @@
 
 RCS_ID("$Id: EONSAddOns.m,v 1.4 2003/02/04 15:16:58 mirko Exp $")
 
-#import <Foundation/Foundation.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSArray.h>
+#import <Foundation/NSLock.h>
+#import <Foundation/NSUserDefaults.h>
+#import <Foundation/NSNotification.h>
+#import <Foundation/NSThread.h>
+#import <Foundation/NSException.h>
+#import <Foundation/NSDebug.h>
 
 #import <EOControl/EONSAddOns.h>
 #import <EOControl/EODebug.h>
 
+static BOOL GSStrictWO451Flag = NO;
+
+BOOL
+GSUseStrictWO451Compatibility(NSString *key)
+{
+  static BOOL read = NO;
+  if (read == NO)
+    {
+      NSLock *lock = [GDL2GlobalLockVendor globalLock];
+      [lock lock];
+      NS_DURING
+        if (read == NO)
+          {
+            NSUserDefaults *defaults;
+            defaults = [NSUserDefaults standardUserDefaults];
+            GSStrictWO451Flag
+              = [defaults boolForKey: @"GSUseStrictWO451Compatibility"];
+            read = YES;
+          }
+      NS_HANDLER
+        [lock unlock];
+        [localException raise];
+      NS_ENDHANDLER
+      [lock unlock];
+    }
+  return GSStrictWO451Flag;
+}
 
 @implementation NSObject (NSObjectPerformingSelector)
 
@@ -418,11 +452,14 @@
 
 @end
 
address@hidden NSObject (EOCOmpareOnNameSupport)
+- (NSString *)name;
address@hidden
 @implementation NSObject (EOCompareOnName)
 
 - (NSComparisonResult)eoCompareOnName: (id)object
 {
-  return [(NSString *)[(id)self name] compare: [object name]];
+  return [[self name] compare: [(NSObject *)object name]];
 }
 
 @end
@@ -432,6 +469,82 @@
 - (BOOL)isYorYES
 {
   return ([self isEqual: @"Y"] || [self isEqual: @"YES"]);
+}
+
address@hidden
+
address@hidden GDL2GlobalLockVendor (private)
++ (void)_setupLocks:(NSNotification *)notif;
address@hidden
+
address@hidden GDL2GlobalLockVendor
+
+static NSLock          *lock  = nil;
+static NSRecursiveLock *rlock = nil;
+
+/*
+ * Depending on whether we are multithreaded or not, we
+ * setup for the becomeMultithreadedNotification to
+ * invoke _setupLocks: or invoke it directly.  This method
+ * is invoked once by the runtime under a lock and
+ * therefor allows thread safe access to global variables.
+ */
++ (void)initialize
+{
+  if (self == [GDL2GlobalLockVendor class])
+    {
+      if ([NSThread isMultiThreaded] == YES)
+       {
+         [self _setupLocks: nil];
+       }
+      else
+       {
+         NSNotificationCenter *nc;
+         nc = [NSNotificationCenter defaultCenter];
+         [nc addObserver: self
+             selector:@selector(_setupLocks:)
+             name: NSWillBecomeMultiThreadedNotification
+             object: nil];
+       }
+    }
+}
+
+/*
+ * Setup globalLock and globalRecursiveLock.  This method should 
+ * only be called from a thread safe context (i.e. from +initialze
+ * or during NSWillBecomeMultiThreadedNotification).
+ */
++ (void)_setupLocks:(NSNotification *)notif
+{
+  if (lock == nil && rlock == nil)
+    {
+      lock  = [NSLock new];
+      rlock = [NSRecursiveLock new];
+    }
+  else
+    {
+      NSLog(@"%@ - +%@ called multiple times!",
+           NSStringFromClass([self class]),
+           NSStringFromSelector(_cmd));
+    }
+}
+
+/**
+ * Returns a global NSLock, if the process is multithreaded.
+ * Otherwise returns nil.
+ */
++ (NSLock *)globalLock
+{
+  return lock;
+}
+
+/**
+ * Returns a global NSRecursiveLock, if the process is multithreaded.
+ * Otherwise returns nil.
+ */
++ (NSRecursiveLock *)globalRecursiveLock
+{
+  return rlock;
 }
 
 @end
/* 
   EOKeyValueCoding.h

   Copyright (C) 2000 Free Software Foundation, Inc.

   Author: Mirko Viviani <address@hidden>
   Date: February 2000

   Modified: David Ayers <address@hidden>
   Date: February 2003

   This file is part of the GNUstep Database 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; see the file COPYING.LIB.
   If not, write to the Free Software Foundation,
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#ifndef __EOKeyValueCoding_h__
#define __EOKeyValueCoding_h__

#import <Foundation/NSObject.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSDictionary.h>

/**
 * GDL2 aims to be compatible with EOF of WebObjects 4.5 and expects to be
 * compiled with gnustep-base and the current version of Mac OS X.  
 * As many of the EOKeyValueCoding methods have moved to NSKeyValueCoding,
 * GDL2 merely implements those methods which are not part of NSKeyValueCoding
 * or reimplements those methods to insure WebObjects 4.5 compatibility.
 */
@interface NSObject (EOKeyValueCoding)

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (id)valueForKey: (NSString *)key;

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (void)takeValue: (id)value forKey: (NSString *)key;

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (id)storedValueForKey: (NSString *)key;

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (void)takeStoredValue: (id)value forKey: (NSString *)key;


/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
+ (BOOL)accessInstanceVariablesDirectly;

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
+ (BOOL)useStoredAccessor;


/**
 * Does nothing.  Key bindings are currently not cached so there is no
 * need to flush them.  This method exists for API compatibility.
 */
+ (void)flushAllKeyBindings;


/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (id)handleQueryWithUnboundKey: (NSString *)key;

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (void)handleTakeValue: (id)value forUnboundKey: (NSString *)key;

/**
 * This method is invoked by the NSKeyValueCoding mechanism when an attempt
 * is made to set an null value for a scalar attribute.  This implementation
 * raises an NSInvalidArgument excaption. <br/>
 * The NSKeyValueCoding -unableToSetNilForKey: is overriden to invoke this
 * method instead.  (Here we silently rely on the runtime to pick the
 * GDL2 category in favor of the one in gnustep-base or Foundation.)
 */
- (void)unableToSetNullForKey: (NSString *)key;

@end

@interface NSObject (EOKeyValueCodingAdditions)

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (id)valueForKeyPath: (NSString *)keyPath;

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (void)takeValue: (id)value forKeyPath: (NSString *)keyPath;

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (NSDictionary *)valuesForKeys: (NSArray *)keys;

/**
 * Unimplemented here.  Relies on NSKeyValueCoding.
 */
- (void)takeValuesFromDictionary: (NSDictionary *)dictionary; 

@end

@interface NSArray (EOKeyValueCoding)
- (id)valueForKey: (NSString *)key;
- (id)valueForKeyPath: (NSString *)keyPath;
- (id)computeSumForKey: (NSString *)key;
- (id)computeAvgForKey: (NSString *)key;
- (id)computeCountForKey: (NSString *)key;
- (id)computeMaxForKey: (NSString *)key;
- (id)computeMinForKey: (NSString *)key;
@end


@interface NSDictionary (EOKeyValueCoding)
- (id)valueForKey: (NSString *)key;
@end


@interface NSMutableDictionary (EOKeyValueCoding)
- (void)takeValue: (id)value 
           forKey: (NSString*)key;
@end


@interface NSObject (EOKVCPAdditions2)
- (void)smartTakeValue: (id)anObject 
                forKey: (NSString *)aKey;
- (void)smartTakeValue: (id)anObject 
            forKeyPath: (NSString *)aKeyPath;
- (void)takeStoredValue: value 
             forKeyPath: (NSString *)key;
- (id)storedValueForKeyPath: (NSString *)key;
#if !FOUNDATION_HAS_KVC
- (void)takeStoredValuesFromDictionary: (NSDictionary *)dictionary;
#endif
- (NSDictionary *)valuesForKeyPaths: (NSArray *)keyPaths;
- (NSDictionary *)storedValuesForKeyPaths: (NSArray *)keyPaths;
@end


extern NSString *EOUnknownKeyException;
extern NSString *EOTargetObjectUserInfoKey;
extern NSString *EOUnknownUserInfoKey;

#endif /* __EOKeyValueCoding_h__ */
/** EOKeyValueCoding.m Copyright (C) 1996-2002 Free Software Foundation, Inc. Author: Mircea Oancea Date: November 1996 Author: Mirko Viviani Date: February 2000 Author: Manuel Guesdon Date: January 2002 $Revision: 1.7 $ $Date: 2003/03/21 20:41:07 $ This file is part of the GNUstep Database 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; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. **/ #include "config.h" RCS_ID("$Id: EOKeyValueCoding.m,v 1.7 2003/03/21 20:41:07 mguesdon Exp $") #import #import #import #import #import #import #import #import #import #import #import #import #include #include #import #import #import #import #include /* * EOKeyValueCodingAdditions implementation */ @implementation NSObject (EOKVCPAdditions2) /** if key is a bidirectional rel, use addObject:toBothSidesOfRelationship otherwise call takeValue:forKey: **/ - (void)smartTakeValue: (id)anObject forKey: (NSString *)aKey { [self takeValue: anObject forKey: aKey]; } - (void)smartTakeValue: (id)anObject forKeyPath: (NSString *)aKeyPath { NSRange r = [aKeyPath rangeOfString: @"."]; if (r.length == 0) { [self smartTakeValue: anObject forKey: aKeyPath]; } else { NSString *key = [aKeyPath substringToIndex: r.location]; NSString *path = [aKeyPath substringFromIndex: NSMaxRange(r)]; [[self valueForKey: key] smartTakeValue: anObject forKeyPath: path]; } } - (void)takeStoredValue: value forKeyPath: (NSString *)key { NSArray *pathArray; NSString *path; id obj = self; int i, count; EOFLOGObjectFnStartCond(@"EOKVC"); pathArray = [key componentsSeparatedByString:@"."]; count = [pathArray count]; for (i = 0; i < (count - 1); i++) { path = [pathArray objectAtIndex: i]; obj = [obj valueForKey: path]; } path = [pathArray lastObject]; [obj takeStoredValue: value forKey: path]; EOFLOGObjectFnStopCond(@"EOKVC"); } - (id)storedValueForKeyPath: (NSString *)key { NSArray *pathArray = nil; NSString *path; id obj = self; int i, count; EOFLOGObjectFnStartCond(@"EOKVC"); pathArray = [key componentsSeparatedByString:@"."]; count = [pathArray count]; for(i=0; i < (count-1); i++) { path = [pathArray objectAtIndex:i]; obj = [obj valueForKey:path]; } path = [pathArray lastObject]; obj=[obj storedValueForKey:path]; EOFLOGObjectFnStopCond(@"EOKVC"); return obj; } #if !FOUNDATION_HAS_KVC - (void)takeStoredValuesFromDictionary: (NSDictionary *)dictionary { NSEnumerator *keyEnum; id key; id val; EOFLOGObjectFnStartCond(@"EOKVC"); keyEnum = [dictionary keyEnumerator]; while ((key = [keyEnum nextObject])) { val = [dictionary objectForKey: key]; if ([val isKindOfClass: [[EONull null] class]]) val = nil; [self takeStoredValue: val forKey: key]; } EOFLOGObjectFnStopCond(@"EOKVC"); } #endif /* !FOUNDATION_HAS_KVC */ - (NSDictionary *)storedValuesForKeyPaths: (NSArray *)keyPaths { NSDictionary *values = nil; int i, n; NSMutableArray *newKeyPaths = nil; NSMutableArray *newVals = nil; EONull *null; EOFLOGObjectFnStartCond(@"EOKVC"); n = [keyPaths count]; newKeyPaths = [[[NSMutableArray alloc] initWithCapacity: n] autorelease]; newVals = [[[NSMutableArray alloc] initWithCapacity: n] autorelease]; null = (EONull *)[EONull null]; for (i = 0; i < n; i++) { id keyPath = [keyPaths objectAtIndex: i]; id val = nil; NS_DURING //DEBUG Only ? { val = [self storedValueForKeyPath: keyPath]; } NS_HANDLER { NSLog(@"EXCEPTION %@", localException); NSDebugMLog(@"EXCEPTION %@", localException); [localException raise]; } NS_ENDHANDLER; if (val == nil) val = null; [newKeyPaths addObject: keyPath]; [newVals addObject: val]; } values = [NSDictionary dictionaryWithObjects: newVals forKeys: newKeyPaths]; EOFLOGObjectFnStopCond(@"EOKVC"); return values; } - (NSDictionary *)valuesForKeyPaths: (NSArray *)keyPaths { NSDictionary *values = nil; int i; int n; NSMutableArray *newKeyPaths; NSMutableArray *newVals; EONull *null; EOFLOGObjectFnStartCond(@"EOKVC"); n = [keyPaths count]; newKeyPaths = [[[NSMutableArray alloc] initWithCapacity: n] autorelease]; newVals = [[[NSMutableArray alloc] initWithCapacity: n] autorelease]; null = (EONull *)[EONull null]; for (i = 0; i < n; i++) { id keyPath = [keyPaths objectAtIndex: i]; id val = nil; NS_DURING //DEBUG Only ? { val = [self valueForKeyPath: keyPath]; } NS_HANDLER { NSLog(@"EXCEPTION %@", localException); NSDebugMLog(@"EXCEPTION %@",localException); [localException raise]; } NS_ENDHANDLER; if (val == nil) val = null; [newKeyPaths addObject: keyPath]; [newVals addObject: val]; } values = [NSDictionary dictionaryWithObjects: newVals forKeys: newKeyPaths]; EOFLOGObjectFnStopCond(@"EOKVC"); return values; } @end @implementation NSArray (EOKeyValueCoding) - (id)valueForKey: (NSString *)key { id result = nil; const char *str; EOFLOGObjectFnStartCond(@"EOKVC"); //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", // key); str=[key cString]; if (str && *str == '@') { if ([key length] > 1) { if ([key isEqualToString: @"@count"]) //the only known case because we haven't implemented custom operators result = [super valueForKey: @"count"]; else // for unknwon case: call computeXXForKey:nil { NSMutableString *selString = [NSMutableString stringWithCapacity:10]; SEL computeSelector; char l = str[1]; if (islower(l)) l = toupper(l); [selString appendString: @"compute"]; [selString appendString: [NSString stringWithCString: &l length: 1]]; [selString appendString: [NSString stringWithCString: &str[2]]]; [selString appendString: @"ForKey:"]; computeSelector = NSSelectorFromString(selString); result = [self performSelector: computeSelector withObject: nil]; } } } else if ([key isEqualToString: @"count"]) //Special case: Apple Doc is wrong; here we return -count { static BOOL warnedCount = NO; if (warnedCount == NO) { warnedCount = YES; NSWarnLog(@"use of special 'count' key may works differently with only foundation base", ""); } result = [super valueForKey: key]; } else { result = [self resultsOfPerformingSelector: @selector(valueForKey:) withObject: key defaultResult: [EONull null]]; } EOFLOGObjectFnStopCond(@"EOKVC"); return result; } - (id)valueForKeyPath: (NSString *)keyPath { id result = nil; const char *str; EOFLOGObjectFnStartCond(@"EOKVC"); //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPath=%@", // keyPath); str = [keyPath cString]; if (str && *str == '@') { if ([keyPath length] > 1) { NSMutableString *selString = [NSMutableString stringWithCapacity: 10]; NSArray *pathArray = [keyPath componentsSeparatedByString: @"."]; NSString *fn = [pathArray objectAtIndex:0]; NSString *key = nil; SEL computeSelector; char l; str = [fn cString]; l = str[1]; if (islower(l)) l = toupper(l); [selString appendString: @"compute"]; [selString appendString: [NSString stringWithCString: &l length: 1]]; [selString appendString: [NSString stringWithCString: &str[2]]]; [selString appendString: @"ForKey:"]; computeSelector = NSSelectorFromString(selString); if ([pathArray count] > 1) { key = [pathArray objectAtIndex: 1]; result = [self performSelector: computeSelector withObject: key]; } else result = [self performSelector: computeSelector withObject: @""]; if (result && [pathArray count] > 2) { NSArray *rightKeyPathArray = [pathArray subarrayWithRange: NSMakeRange(2, [pathArray count] - 2)]; NSString *rightKeyPath = [rightKeyPathArray componentsJoinedByString: @"."]; result = [result valueForKeyPath: rightKeyPath]; } } } else if ([keyPath isEqualToString: @"count"]) //Special case: Apple Doc is wrong; here we return -count { static BOOL warnedCount = NO; if (warnedCount == NO) { warnedCount = YES; NSWarnLog(@"use of special 'count' key may works differently with only foundation base", ""); } result = [super valueForKeyPath: keyPath]; } else result = [self resultsOfPerformingSelector: @selector(valueForKeyPath:) withObject: keyPath defaultResult: [EONull null]]; EOFLOGObjectFnStopCond(@"EOKVC"); return result; } - (id)computeSumForKey: (NSString *)key { NSEnumerator *arrayEnum; NSDecimalNumber *item, *ret; EOFLOGObjectFnStartCond(@"EOKVC"); arrayEnum = [self objectEnumerator]; ret = [NSDecimalNumber zero]; while ((item = [arrayEnum nextObject])) [ret decimalNumberByAdding: [item valueForKey:key]]; EOFLOGObjectFnStopCond(@"EOKVC"); return ret; } - (id)computeAvgForKey: (NSString *)key { NSEnumerator *arrayEnum; NSDecimalNumber *item, *ret; EOFLOGObjectFnStartCond(@"EOKVC"); arrayEnum = [self objectEnumerator]; ret = [NSDecimalNumber zero]; while ((item = [arrayEnum nextObject])) [ret decimalNumberByAdding: [item valueForKey:key]]; ret = [ret decimalNumberByDividingBy: [NSDecimalNumber decimalNumberWithMantissa: [self count] exponent: 0 isNegative:NO]]; EOFLOGObjectFnStopCond(@"EOKVC"); return ret; } - (id)computeCountForKey: (NSString *)key { id ret; EOFLOGObjectFnStartCond(@"EOKVC"); ret = [NSNumber numberWithInt: [self count]]; EOFLOGObjectFnStopCond(@"EOKVC"); return ret; } - (id)computeMaxForKey: (NSString *)key { NSEnumerator *arrayEnum; NSDecimalNumber *item, *max; id value = nil; EOFLOGObjectFnStartCond(@"EOKVC"); arrayEnum = [self objectEnumerator]; item = [arrayEnum nextObject]; value = [item valueForKey:key]; max = value; if (item != nil) { while ((item = [arrayEnum nextObject])) { value = [item valueForKey:key]; if ([max compare: value] == NSOrderedAscending) max = value; } } EOFLOGObjectFnStopCond(@"EOKVC"); return max; } - (id)computeMinForKey: (NSString *)key { NSEnumerator *arrayEnum; NSDecimalNumber *item, *min; id value = nil; EOFLOGObjectFnStartCond(@"EOKVC"); arrayEnum = [self objectEnumerator]; item = [arrayEnum nextObject]; value = [item valueForKey:key]; min = value; if (item != nil) { while ((item = [arrayEnum nextObject])) { value = [item valueForKey:key]; if ([min compare: value] == NSOrderedDescending) min = value; } } EOFLOGObjectFnStopCond(@"EOKVC"); return min; } @end @implementation NSDictionary (EOKeyValueCoding) #if !FOUNDATION_HAS_KVC - (id)valueForKey:(NSString *)key { id value; EOFLOGObjectFnStartCond(@"EOKVC"); EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); value = [self objectForKey: key]; if (!value) { if ([key isEqualToString: @"allValues"]) { static BOOL warnedAllValues = NO; if (warnedAllValues == NO) { warnedAllValues = YES; NSWarnLog(@"use of special 'allValues' key works differently with only foundation base", ""); } value = [self allValues]; } else if ([key isEqualToString: @"allKeys"]) { static BOOL warnedAllKeys = NO; if (warnedAllKeys == NO) { warnedAllKeys = YES; NSWarnLog(@"use of special 'allKeys' key works differently with only foundation base", ""); } value = [self allKeys]; } else if ([key isEqualToString: @"count"]) { static BOOL warnedCount = NO; if (warnedCount == NO) { warnedCount = YES; NSWarnLog(@"use of special 'count' key works differently with only foundation base", ""); } value = [NSNumber numberWithInt: [self count]]; } } //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@ value: %p (class %@)", // key, value, [value class]); EOFLOGObjectFnStopCond(@"EOKVC"); return value; } - (id)storedValueForKey: (NSString *)key { id value; EOFLOGObjectFnStartCond(@"EOKVC"); //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", // key); value = [self objectForKey: key]; if (!value) { if ([key isEqualToString: @"allValues"]) value = [self allValues]; else if ([key isEqualToString: @"allKeys"]) value = [self allKeys]; else if ([key isEqualToString: @"count"]) value = [NSNumber numberWithInt: [self count]]; } //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@ value: %p (class=%@)", // key, value, [value class]); EOFLOGObjectFnStopCond(@"EOKVC"); return value; } #endif /* !FOUNDATION_HAS_KVC */ //MG - (id)valueForKeyPath: (NSString*)keyPath { id value = nil; EOFLOGObjectFnStartCond(@"EOKVC"); //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPath=\"address@hidden"", // keyPath); if ([keyPath hasPrefix: @"'"]) //user defined composed key { NSMutableArray *keyPathArray = [[[[keyPath stringByDeletingPrefix: @"'"] componentsSeparatedByString: @"."] mutableCopy] autorelease]; NSMutableString *key = [NSMutableString string]; //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); while ([keyPathArray count] > 0) { id tmpKey; //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); tmpKey = [keyPathArray objectAtIndex: 0]; //EOFLOGObjectLevelArgs(@"EOKVC", @"tmpKey=%@", tmpKey); [keyPathArray removeObjectAtIndex: 0]; if ([key length] > 0) [key appendString: @"."]; if ([tmpKey hasSuffix: @"'"]) { tmpKey = [tmpKey stringByDeletingSuffix: @"'"]; [key appendString: tmpKey]; break; } else [key appendString: tmpKey]; //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); } //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); value = [self valueForKey: key]; //EOFLOGObjectLevelArgs(@"EOKVC",@"key=%@ tmpValue: %p (class=%@)", // key,value,[value class]); if (value && [keyPathArray count] > 0) { NSString *rightKeyPath = [keyPathArray componentsJoinedByString: @"."]; //EOFLOGObjectLevelArgs(@"EOKVC", @"rightKeyPath=%@", // rightKeyPath); value = [value valueForKeyPath: rightKeyPath]; } } else { //return super valueForKeyPath:keyPath only if there's no object for entire key keyPath value = [self objectForKey: keyPath]; EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=%@ tmpValue: %p (class=%@)", keyPath,value,[value class]); /* if([value isEqual:[EONull null]] == YES) //??? value=nil; else */ if (!value) value = [super valueForKeyPath: keyPath]; } //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=%@ value: %p (class=%@)", // keyPath,value,[value class]); EOFLOGObjectFnStopCond(@"EOKVC"); return value; } //MG #endif /* !FOUNDATION_HAS_KVC */ - (id)storedValueForKeyPath: (NSString*)keyPath { id value = nil; EOFLOGObjectFnStartCond(@"EOKVC"); //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=\"address@hidden"", // keyPath); if ([keyPath hasPrefix: @"'"]) //user defined composed key { NSMutableArray *keyPathArray = [[[[keyPath stringByDeletingPrefix: @"'"] componentsSeparatedByString: @"."] mutableCopy] autorelease]; NSMutableString *key = [NSMutableString string]; //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); while ([keyPathArray count] > 0) { id tmpKey; //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); tmpKey = [keyPathArray objectAtIndex: 0]; //EOFLOGObjectLevelArgs(@"EOKVC", @"tmpKey=%@", tmpKey); [keyPathArray removeObjectAtIndex: 0]; if ([key length] > 0) [key appendString: @"."]; if ([tmpKey hasSuffix: @"'"]) { tmpKey = [tmpKey stringByDeletingSuffix: @"'"]; [key appendString: tmpKey]; break; } else [key appendString: tmpKey]; //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); } //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); value = [self storedValueForKey: key]; //EOFLOGObjectLevelArgs(@"EOKVC",@"key=%@ tmpValue: %p (class=%@)", // key,value,[value class]); if (value && [keyPathArray count] > 0) { NSString *rightKeyPath = [keyPathArray componentsJoinedByString: @"."]; EOFLOGObjectLevelArgs(@"EOKVC", @"rightKeyPath=%@", rightKeyPath); value = [value storedValueForKeyPath: rightKeyPath]; } } else { //return super valueForKeyPath:keyPath only if there's no object for entire key keyPath value = [self objectForKey: keyPath]; //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=%@ tmpValue: %p (class=%@)", // keyPath,value,[value class]); /* if([value isEqual:[EONull null]] == YES) //??? value=nil; else */ if (!value) value = [super storedValueForKeyPath: keyPath]; } //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=%@ value: %p (class=%@)", // keyPath,value,[value class]); EOFLOGObjectFnStopCond(@"EOKVC"); return value; } @end @interface NSMutableDictionary(EOKeyValueCodingPrivate) - (void)takeValue: (id)value forKeyPath: (NSString *)keyPath isSmart: (BOOL)smartFlag; @end @implementation NSMutableDictionary (EOKeyValueCoding) #if !FOUNDATION_HAS_KVC - (void)takeValue: (id)value forKey: (NSString *)key { EOFLOGObjectFnStartCond(@"EOKVC"); if (value) [self setObject: value forKey: key]; else [self removeObjectForKey: key]; EOFLOGObjectFnStopCond(@"EOKVC"); } - (void)takeStoredValue: (id)value forKey: (NSString *)key { EOFLOGObjectFnStartCond(@"EOKVC"); if (value) [self setObject: value forKey: key]; else [self removeObjectForKey: key]; EOFLOGObjectFnStopCond(@"EOKVC"); } #endif /* !FOUNDATION_HAS_KVC */ - (void)smartTakeValue: (id)value forKeyPath: (NSString*)keyPath { [self takeValue:value forKeyPath:keyPath isSmart:YES]; } #if !FOUNDATION_HAS_KVC - (void)takeValue: (id)value forKeyPath: (NSString *)keyPath { [self takeValue:value forKeyPath:keyPath isSmart:NO]; } #endif /* !FOUNDATION_HAS_KVC */ - (void)takeValue: (id)value forKeyPath: (NSString *)keyPath isSmart: (BOOL)smartFlag { EOFLOGObjectFnStartCond(@"EOKVC"); //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPath=\"address@hidden"", // keyPath); if ([keyPath hasPrefix: @"'"]) //user defined composed key { NSMutableArray *keyPathArray = [[[[keyPath stringByDeletingPrefix: @"'"] componentsSeparatedByString: @"."] mutableCopy] autorelease]; NSMutableString *key = [NSMutableString string]; //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); while ([keyPathArray count] > 0) { id tmpKey; //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); tmpKey = RETAIN([keyPathArray objectAtIndex: 0]); //EOFLOGObjectLevelArgs(@"EOKVC", @"tmpKey=%@", tmpKey); [keyPathArray removeObjectAtIndex: 0]; if ([key length] > 0) [key appendString: @"."]; if ([tmpKey hasSuffix: @"'"]) { ASSIGN(tmpKey, [tmpKey stringByDeletingSuffix: @"'"]); [key appendString: tmpKey]; break; } else [key appendString: tmpKey]; RELEASE(tmpKey); //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); } //EOFLOGObjectLevelArgs(@"EOKVC",@"key=%@",key); //EOFLOGObjectLevelArgs(@"EOKVC",@"left keyPathArray=\"address@hidden"", // keyPathArray); if ([keyPathArray count] > 0) { id obj = [self objectForKey: key]; if (obj) { NSString *rightKeyPath = [keyPathArray componentsJoinedByString: @"."]; //EOFLOGObjectLevelArgs(@"EOKVC",@"rightKeyPath=\"address@hidden"", // rightKeyPath); if (smartFlag) [obj smartTakeValue: value forKeyPath: rightKeyPath]; else [obj takeValue: value forKeyPath: rightKeyPath]; } } else { if (value) [self setObject: value forKey: key]; else [self removeObjectForKey: key]; } } else { if (value) [self setObject: value forKey: keyPath]; else [self removeObjectForKey: keyPath]; } EOFLOGObjectFnStopCond(@"EOKVC"); } - (void)takeStoredValue: (id)value forKeyPath: (NSString *)keyPath { EOFLOGObjectFnStartCond(@"EOKVC"); //EOFLOGObjectLevelArgs(@"EOKVC",@"keyPath=\"address@hidden"", // keyPath); if ([keyPath hasPrefix: @"'"]) //user defined composed key { NSMutableArray *keyPathArray = [[[[keyPath stringByDeletingPrefix: @"'"] componentsSeparatedByString: @"."] mutableCopy] autorelease]; NSMutableString *key = [NSMutableString string]; //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); while ([keyPathArray count] > 0) { id tmpKey; //EOFLOGObjectLevelArgs(@"EOKVC", @"keyPathArray=%@", keyPathArray); tmpKey = [keyPathArray objectAtIndex: 0]; //EOFLOGObjectLevelArgs(@"EOKVC", @"tmpKey=%@", tmpKey); [keyPathArray removeObjectAtIndex: 0]; if ([key length] > 0) [key appendString: @"."]; if ([tmpKey hasSuffix: @"'"]) { tmpKey = [tmpKey stringByDeletingSuffix: @"'"]; [key appendString: tmpKey]; break; } else [key appendString: tmpKey]; //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); } //EOFLOGObjectLevelArgs(@"EOKVC", @"key=%@", key); //EOFLOGObjectLevelArgs(@"EOKVC",@"left keyPathArray=\"address@hidden"", // keyPathArray); if ([keyPathArray count] > 0) { id obj = [self objectForKey: key]; if (obj) { NSString *rightKeyPath = [keyPathArray componentsJoinedByString: @"."]; //EOFLOGObjectLevelArgs(@"EOKVC",@"rightKeyPath=\"address@hidden"", // rightKeyPath); [obj takeStoredValue: value forKeyPath: rightKeyPath]; } } else { if (value) [self setObject: value forKey: key]; else [self removeObjectForKey: key]; } } else { if (value) [self setObject: value forKey: keyPath]; else [self removeObjectForKey: keyPath]; } EOFLOGObjectFnStopCond(@"EOKVC"); } @end
reply via email to

[Prev in Thread] Current Thread [Next in Thread]