1/* 2 Copyright (C) 2000-2005 SKYRIX Software AG 3 4 This file is part of SOPE. 5 6 SOPE is free software; you can redistribute it and/or modify it under 7 the terms of the GNU Lesser General Public License as published by the 8 Free Software Foundation; either version 2, or (at your option) any 9 later version. 10 11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 14 License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with SOPE; see the file COPYING. If not, write to the 18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 19 02111-1307, USA. 20*/ 21 22#include "EOQualifier+CtxEval.h" 23#import <EOControl/EOKeyValueCoding.h> 24#import <EOControl/EONull.h> 25#include "common.h" 26 27#if LIB_FOUNDATION_LIBRARY 28# import <objc/objc-api.h> 29# import <objc/objc.h> 30# import <extensions/objc-runtime.h> 31#elif GNUSTEP_BASE_LIBRARY 32#if __GNU_LIBOBJC__ >= 20100911 33# import <objc/runtime.h> 34#else 35# import <objc/objc-api.h> 36#endif 37#else 38# import <objc/objc.h> 39#endif 40 41static inline int countSelArgs(SEL _sel) { 42 register const char *selName; 43 44 if ((selName = sel_getName(_sel))) { 45 register int count; 46 47 for (count = 0; *selName; selName++) { 48 if (*selName == ':') 49 count++; 50 } 51 return count + 2; 52 } 53 else 54 return -1; 55} 56 57@implementation EOQualifier(ContextEvaluation) 58 59- (BOOL)evaluateWithObject:(id)_object context:(id)_context { 60 [self doesNotRecognizeSelector:_cmd]; /* subclass */ 61 return NO; 62} 63 64@end /* EOQualifier(ContextEvaluation) */ 65 66@implementation NSArray(ContextEvaluation) 67 68- (NSArray *)filteredArrayUsingQualifier:(EOQualifier *)_qualifier 69 context:(id)_context 70{ 71 NSMutableArray *a = nil; 72 unsigned i, count; 73 74 for (i = 0, count = [self count]; i < count; i++) { 75 id o; 76 77 o = [self objectAtIndex:i]; 78 79 if ([_qualifier evaluateWithObject:o context:_context]) { 80 if (a == nil) a = [NSMutableArray arrayWithCapacity:count]; 81 [a addObject:o]; 82 } 83 } 84 return a ? [[a copy] autorelease] : [NSArray array]; 85} 86 87@end /* NSArray(ContextEvaluation) */ 88 89@implementation EOAndQualifier(ContextEvaluation) 90 91- (BOOL)evaluateWithObject:(id)_object context:(id)_context { 92 unsigned i; 93 IMP objAtIdx; 94 NSArray *qs; 95 96 qs = [self qualifiers]; 97 objAtIdx = [qs methodForSelector:@selector(objectAtIndex:)]; 98 99 for (i = 0; i < [qs count]; i++) { 100 EOQualifier *q; 101 102 q = objAtIdx(qs, @selector(objectAtIndex:), i); 103 104 if (![q evaluateWithObject:_object context:_context]) 105 return NO; 106 } 107 return YES; 108} 109 110@end /* EOAndQualifier(ContextEvaluation) */ 111 112@implementation EOOrQualifier(ContextEvaluation) 113 114- (BOOL)evaluateWithObject:(id)_object context:(id)_context { 115 unsigned i; 116 IMP objAtIdx; 117 NSArray *qs; 118 119 qs = [self qualifiers]; 120 objAtIdx = [qs methodForSelector:@selector(objectAtIndex:)]; 121 122 for (i = 0; i < [qs count]; i++) { 123 EOQualifier *q; 124 125 q = objAtIdx(qs, @selector(objectAtIndex:), i); 126 127 if ([q evaluateWithObject:_object context:_context]) 128 return YES; 129 } 130 return NO; 131} 132 133@end /* EOOrQualifier(ContextEvaluation) */ 134 135@implementation EONotQualifier(ContextEvaluation) 136 137- (BOOL)evaluateWithObject:(id)_object context:(id)_context { 138 return 139 [[self qualifier] evaluateWithObject:_object context:_context] 140 ? NO : YES; 141} 142 143@end /* EONotQualifier(ContextEvaluation) */ 144 145@implementation EOKeyValueQualifier(ContextEvaluation) 146 147- (BOOL)evaluateWithObject:(id)_object context:(id)_context { 148 static EONull *null = nil; 149 id lv, rv; 150 union { 151 IMP m; 152 BOOL (*unary)(id, SEL); 153 BOOL (*binary)(id, SEL, id); 154 BOOL (*ctx)(id, SEL, id, id); 155 } m; 156 SEL op; 157 158 op = [self selector]; 159 lv = [_object valueForKeyPath:[self key]]; 160 rv = [self value]; 161 162 if (null == nil) null = [EONull null]; 163 if (lv == nil) lv = null; 164 if (rv == nil) rv = null; 165 166 if ((m.m = [lv methodForSelector:op]) == NULL) { 167 /* no such operator method ! */ 168 [lv doesNotRecognizeSelector:op]; 169 return NO; 170 } 171 switch (countSelArgs(op)) { 172 case 0: 173 case 1: 174 NSLog(@"%s: called with invalid selector %@", __PRETTY_FUNCTION__, 175 NSStringFromSelector(op)); 176 return NO; 177 178 case 2: 179 return m.unary(lv, op); 180 case 3: 181 return m.binary(lv, op, rv); 182 default: 183 return m.ctx(lv, op, rv, _context); 184 } 185} 186 187@end /* EOKeyValueQualifier(ContextEvaluation) */ 188 189@implementation EOKeyComparisonQualifier(ContextEvaluation) 190 191- (BOOL)evaluateWithObject:(id)_object context:(id)_context { 192 static EONull *null = nil; 193 id lv, rv; 194 union { 195 IMP m; 196 BOOL (*unary)(id, SEL); 197 BOOL (*binary)(id, SEL, id); 198 BOOL (*ctx)(id, SEL, id, id); 199 } m; 200 SEL op; 201 202 lv = [_object valueForKeyPath:[self leftKey]]; 203 rv = [_object valueForKeyPath:[self rightKey]]; 204 if (null == nil) null = [EONull null]; 205 if (lv == nil) lv = null; 206 if (rv == nil) rv = null; 207 208 op = [self selector]; 209 210 if ((m.m = (void *)[lv methodForSelector:op]) == NULL) { 211 /* no such operator method ! */ 212 [lv doesNotRecognizeSelector:op]; 213 return NO; 214 } 215 switch (countSelArgs(op)) { 216 case 0: 217 case 1: 218 NSLog(@"%s: called with invalid selector %@", __PRETTY_FUNCTION__, 219 NSStringFromSelector(op)); 220 return NO; 221 222 case 2: 223 return m.unary(lv, op); 224 case 3: 225 return m.binary(lv, op, rv); 226 default: 227 return m.ctx(lv, op, rv, _context); 228 } 229} 230 231@end /* EOKeyComparisonQualifier(ContextEvaluation) */ 232 233@implementation NSObject(ImplementedQualifierComparisons2) 234 235- (BOOL)isEqualTo:(id)_object inContext:(id)_context { 236 return [self isEqualTo:_object]; 237} 238- (BOOL)isNotEqualTo:(id)_object inContext:(id)_context { 239 return [self isNotEqualTo:_object]; 240} 241 242- (BOOL)isLessThan:(id)_object inContext:(id)_context { 243 return [self isLessThan:_object]; 244} 245- (BOOL)isGreaterThan:(id)_object inContext:(id)_context { 246 return [self isGreaterThan:_object]; 247} 248- (BOOL)isLessThanOrEqualTo:(id)_object inContext:(id)_context { 249 return [self isLessThanOrEqualTo:_object]; 250} 251- (BOOL)isGreaterThanOrEqualTo:(id)_object inContext:(id)_context { 252 return [self isGreaterThanOrEqualTo:_object]; 253} 254 255- (BOOL)doesContain:(id)_object inContext:(id)_context { 256 return [self doesContain:_object]; 257} 258 259- (BOOL)isLike:(NSString *)_object inContext:(id)_context { 260 return [self isLike:_object]; 261} 262- (BOOL)isCaseInsensitiveLike:(NSString *)_object inContext:(id)_context { 263 return [self isCaseInsensitiveLike:_object]; 264} 265 266@end 267