category on NSObject it eliminates the caching scheme used.
*/
+// TODO: properly use logging framework for debug messages
#if DEBUG
// #define HEAVY_DEBUG 1
// #define USE_EXCEPTION_HANDLERS 1
return self;
}
- (id)init {
- NSLog(@"keypaths can not be created using 'init' ..");
+ [self errorWithFormat:@"keypaths can not be created using 'init' .."];
[NSException raise:@"InvalidUseOfMethodException"
format:@"keypaths can not be created using 'init'"];
return nil;
}
- (void)dealloc {
- if (self->keyPath) {
+ if (self->keyPath != NULL) {
int cnt;
for (cnt = 0; cnt < self->size; cnt++)
[[StringClass alloc] initWithCString:(char *)(info->ckey + 1)];
}
else {
- if (object) {
+ if (object != nil) {
if (object_is_instance(object)) {
+ /*
+ kvcIsPreferredInKeyPath means that for some objects the keys will
+ be probed first. The prominent example is NSDictionary, if you
+ say valueForKey:@"count" you want to resolve to the 'count' key
+ stored in the dictionary, NOT to the -count method of the
+ NSDictionary class.
+ */
if ([object kvcIsPreferredInKeyPath]) {
method = class_get_instance_method(clazz, @selector(valueForKey:));
}
#if HEAVY_DEBUG
- NSLog(@"type is %i, key is '%s'", info->type, info->ckey);
+ [self logWithFormat:@"type is %i, key is '%s'", info->type, info->ckey];
#endif
}
}
static NSString *kpKey = @"keyPath";
static NSString *assocKey = @"association";
static NSString *excName = @"WOKeyPathException";
- static NSString *excReason = @"couldn't get value for a keypath component";
+ static NSString *excReason = @"could not get value for a keypath component";
NSException *e;
NSDictionary *ui;
// execute
if (info->type == WOKeyType_method) {
#if HEAVY_DEBUG
- NSLog(@"get key %s of keyPath %@\n"
+ [self logWithFormat:@"get key %s of keyPath %@\n"
@" from: 0x%08X[%@]\n"
@" via method (ret %c)",
info->ckey, [self keyPath], object,
- NSStringFromClass([object class]), info->retType);
+ NSStringFromClass([object class]), info->retType];
#endif
#if USE_EXCEPTION_HANDLERS
NS_DURING {
if ((info->retType == _C_ID) || (info->retType == _C_CLASS)) {
retValue.object = info->access.method(object, info->extra.sel.get);
#if HEAVY_DEBUG
- NSLog(@" got result 0x%08X[%@]: %@", retValue.object,
+ [self logWithFormat:@" got result 0x%08X[%@]: %@", retValue.object,
NSStringFromClass([retValue.object class]),
- retValue.object);
+ retValue.object];
#endif
}
else {
break;
default:
- NSLog(@"%@: unsupported type '%c' !", self, info->retType);
+ [self errorWithFormat:@"unsupported type '%c' !", info->retType];
[NSException raise:@"WORuntimeException"
format:
@"in WOKeyPathAssociation %@: unsupported type '%c'",
}
else if (info->type == WOKeyType_kvc) {
#if HEAVY_DEBUG
- NSLog(@"get keyPath %@ from %@ via KVC", [self keyPath], object);
+ [self logWithFormat:@"get keyPath %@ from %@ via KVC",
+ [self keyPath], object];
#endif
#if 0
NSLog(@"ckey: %s", info->ckey);
}
else if (info->type == WOKeyType_binding) {
#if HEAVY_DEBUG
- NSLog(@"get keyPath %@ from %@ via binding", [self keyPath], object);
+ [self logWithFormat:@"get keyPath %@ from %@ via binding",
+ [self keyPath], object];
#endif
retValue.object =
}
else { // unknown || ivar
#if HEAVY_DEBUG
- NSLog(@"unknown info type for keyPath %@ from %@ !!",
- [self keyPath], object);
+ [self logWithFormat:@"unknown info type for keyPath %@ from %@ !!",
+ [self keyPath], object];
#endif
retValue.object = nil;
}
static inline id _objectify(unsigned char _type, WOReturnValueHolder *_value) {
id result = nil;
- //NSLog(@"shall convert value of type '%c'", _type);
+ //[self logWithFormat:@"shall convert value of type '%c'", _type];
switch (_type) {
case _C_ID:
break;
default:
- NSLog(@"unsupported type '%c' !", _type);
+ NSLog(@"%s: unsupported type '%c' !", __PRETTY_FUNCTION__, _type);
[NSException raise:@"WORuntimeException"
format:@"in WOKeyPathAssociation: unsupported type '%c'",
_type];
break;
}
- //NSLog(@"made %@[0x%08X].", NSStringFromClass([result class]), result);
+ // NSLog(@"made %@[0x%08X].", NSStringFromClass([result class]), result);
return result;
}
info = (WOKeyPathComponent *)self->keyPath;
retValue = _getComponentValue(self, root, info);
-
+
return (info->type == WOKeyType_method)
? _objectify(info->retType, &retValue)
: retValue.object;
NSCAssert(info->keyLen < 255, @"keysize to big ..");
_fillInfo(self, object, info);
-
+
if (info->type == WOKeyType_method) { // determine set-selector
SEL setSel = _getSetSel(info->ckey, info->keyLen);
if (![object respondsToSelector:setSel]) {
-#if 0
- NSLog(@"%@: Could not set value for key '%s', "
+#if 1
+ [self errorWithFormat:@"Could not set value for key '%s', "
@"object %@ doesn't respond to %@.",
self, info->ckey, object,
- setSel ? NSStringFromSelector(setSel) : @"<NULL>");
+ setSel ? NSStringFromSelector(setSel) : @"<NULL>"];
#endif
return NO;
}
else {
WOSetMethodType sm;
- if ((sm.method = [object methodForSelector:setSel])) {
+ if ((sm.method = [object methodForSelector:setSel]) != NULL) {
switch (info->retType) {
case _C_CLASS:
case _C_ID:
break;
default:
- NSLog(@"%@: cannot set type '%c' yet (key=%s, method=%@) ..",
- self, info->retType, info->ckey,
- NSStringFromSelector(setSel));
+ [self errorWithFormat:
+ @"cannot set type '%c' yet (key=%s, method=%@) ..",
+ info->retType, info->ckey,
+ NSStringFromSelector(setSel)];
[NSException raise:@"WORuntimeException"
format:
@"in WOKeyPathAssociation %@: "
return YES;
}
else {
- NSLog(@"%@: did not find method %@ in object %@",
- self, NSStringFromSelector(setSel), object);
+ [self logWithFormat:@"did not find method %@ in object %@",
+ NSStringFromSelector(setSel), object];
return NO;
}
}
}
else if (info->type == WOKeyType_kvc) { // takeValue:forKey:..
NSCAssert(info->extra.key, @"no key object set ..");
+
+ /*
+ The following check is necessary because starting with Cocoa Foundation
+ v10.3? mutable and immutable dictionary objects are the same class :-(
+
+ To make it worse the _CFDictionaryIsMutable is a private function which
+ might vanish ...
+ */
#if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
APPLE_FOUNDATION_LIBRARY
if([object isKindOfClass:NSCFDictionaryClass] &&
!_CFDictionaryIsMutable((CFDictionaryRef)object))
return NO;
#endif
+
+ /*
+ TODO(hh): Maybe this needs improvement. For non-dictionary like objects
+ (eg WOComponents) this code does the method scanning twice,
+ first we scan the object for method 'key', then the Foundation
+ KVC again scans for the 'key' method prior falling back to
+ handleUnknownKey stuff ...
+ */
+
+#if GNUSTEP_BASE_LIBRARY && ((GNUSTEP_BASE_MAJOR_VERSION >= 1) && \
+ (GNUSTEP_BASE_MINOR_VERSION >= 11))
+ // TODO: also do this for OSX 10.4? probably
+ [object setValue:_value forKey:info->extra.key];
+#else
[object takeValue:_value forKey:info->extra.key];
+#endif
return YES;
}
else if (info->type == WOKeyType_binding) { // setValue:forBinding:
return YES;
}
else {
- NSLog(@"%@: Could not set value for key '%s'.", self, info->ckey);
+ // TODO: use errorWithFormat?
+ [self logWithFormat:@"Could not set value for key '%s'.", info->ckey];
return NO;
}
}
- (void)setValue:(id)_value inComponent:(WOComponent *)_component {
if (debugOn)
- NSLog(@"%@: set value %@ component %@", self, _value, _component);
+ [self logWithFormat:@"set value %@ component %@", _value, _component];
_setValue(self, _value, _component);
}
#if DEBUG
volatile id result;
if (debugOn)
- NSLog(@"%@: get value in component %@", self, _component);
+ [self logWithFormat:@"get value in component %@", _component];
#if USE_EXCEPTION_HANDLERS
NS_DURING {
}
NS_ENDHANDLER;
#endif
+
return result;
-#else
+
+#else /* !DEBUG */
if (debugOn)
- NSLog(@"%@: get value in component %@", self, _component);
+ [self logWithFormat:@"get value in component %@", _component];
return (self->size > 1)
? _getValue(self, _component)
WOKeyPathComponent *info;
if (debugOn)
- NSLog(@"%@: set uint value %i in component %@", self, _value, _wo);
+ [self logWithFormat:@"set uint value %i in component %@", _value, _wo];
if (self->size > 1) {
_setValue(self, uintNumObj(_value), _wo);
switch (info->retType) {
case _C_CHR: {
if (((int)_value < -126) || ((int)_value > 127))
- NSLog(@"%@: value (%i) out of range for char !", self, _value);
+ [self errorWithFormat:
+ @"value (%i) out of range for char!", _value];
sm.cmethod(_wo, setSel, (char)_value);
break;
}
case _C_UCHR: {
if ((_value < 0) || (_value > 255))
- NSLog(@"%@: value (%i) out of range for uchar !", self, _value);
+ [self errorWithFormat:
+ @"value (%i) out of range for uchar!", _value];
sm.ucmethod(_wo, setSel, (unsigned char)_value);
break;
}
return;
}
- NSLog(@"%@: Could not set value for key '%s'.", self, info->ckey);
+ [self errorWithFormat:@"Could not set value for key '%s'.", info->ckey];
}
- (unsigned int)unsignedIntValueInComponent:(WOComponent *)_component {
WOKeyPathComponent *info;
WOReturnValueHolder retValue;
if (debugOn)
- NSLog(@"%@: get uint value in component %@", self, _component);
+ [self logWithFormat:@"get uint value in component %@", _component];
if (self->size > 1)
return [_getValue(self, _component) unsignedIntValue];
}
#if 0
- NSLog(@"ret value object for key '%s' is 0x%08X",
- info->ckey, retValue.object);
- NSLog(@"ret value object class is %@", [retValue.object class]);
+ [self logWithFormat:@"ret value object for key '%s' is 0x%08X",
+ info->ckey, retValue.object];
+ [self logWithFormat:@"ret value object class is %@",
+ [retValue.object class]];
#endif
return [retValue.object unsignedIntValue];
}
WOKeyPathComponent *info;
if (debugOn)
- NSLog(@"%@: set int value %i in component %@", self, _value, _wo);
+ [self logWithFormat:@"set int value %i in component %@", _value, _wo];
if (self->size > 1) {
_setValue(self, intNumObj(_value), _wo);
switch (info->retType) {
case _C_CHR: {
if (((int)_value < -126) || ((int)_value > 127))
- NSLog(@"%@: value (%i) out of range for char !", self, _value);
+ [self errorWithFormat:
+ @"value (%i) out of range for char !", _value];
sm.cmethod(_wo, setSel, (char)_value);
break;
}
case _C_UCHR: {
if ((_value < 0) || (_value > 255))
- NSLog(@"%@: value (%i) out of range for uchar !", self, _value);
+ [self errorWithFormat:
+ @"value (%i) out of range for uchar!", _value];
sm.ucmethod(_wo, setSel, (unsigned char)_value);
break;
}
return;
}
- NSLog(@"%@: Could not set value for key '%s'.", self, info->ckey);
+ [self errorWithFormat:@"Could not set value for key '%s'.", info->ckey];
}
- (int)intValueInComponent:(WOComponent *)_component {
WOKeyPathComponent *info;
WOReturnValueHolder retValue;
if (debugOn)
- NSLog(@"%@: get int value in component %@", self, _component);
+ [self logWithFormat:@"get int value in component %@", _component];
if (self->size > 1)
return [_getValue(self, _component) intValue];
WOKeyPathComponent *info;
if (debugOn)
- NSLog(@"%@: set bool value %i in component %@", self, _value, _wo);
+ [self logWithFormat:@"set bool value %i in component %@", _value, _wo];
if (self->size > 1) {
_setValue(self, [NumberClass numberWithBool:_value], _wo);
[_wo setValue:[NumberClass numberWithBool:_value]
forBinding:info->extra.key];
}
- else {
- NSLog(@"%@: Could not set value for key '%s'.", self, info->ckey);
- }
+ else
+ [self errorWithFormat:@"Could not set value for key '%s'.", info->ckey];
}
- (BOOL)boolValueInComponent:(WOComponent *)_component {
if (debugOn)
- NSLog(@"%@: get bool value in component %@", self, _component);
+ [self logWithFormat:@"get bool value in component %@", _component];
if (self->size > 1)
return [_getValue(self, _component) boolValue];
- (void)setStringValue:(NSString *)_value inComponent:(WOComponent *)_wo {
if (debugOn)
- NSLog(@"%@: set string value '%@' in component %@", self, _value, _wo);
+ [self logWithFormat:@"set string value '%@' in component %@", _value, _wo];
_setValue(self, _value, _wo);
}
- (NSString *)stringValueInComponent:(WOComponent *)_component {
WOKeyPathComponent *info;
WOReturnValueHolder retValue;
-
+
if (debugOn)
- NSLog(@"%@: get string value in component %@", self, _component);
+ [self logWithFormat:@"get string value in component %@", _component];
if (self->size > 1)
return [_getValue(self, _component) stringValue];
/* description */
+- (NSString *)loggingPrefix {
+ return [StringClass stringWithFormat:@"|assoc=%@|", [self keyPath]];
+}
+
- (NSString *)description {
return [StringClass stringWithFormat:@"<%@[0x%08X]: keyPath=%@>",
NSStringFromClass([self class]), self,
--- /dev/null
+/*
+ Copyright (C) 2006 Helge Hess
+*/
+
+#include "SoProductLoader.h"
+#include "SoProductRegistry.h"
+#include "common.h"
+
+@implementation SoProductLoader
+
+- (id)initWithAppName:(NSString *)_appName
+ majorVersion:(NSString *)_mav minorVersion:(NSString *)_miv
+{
+ if ((self = [super init]) != nil) {
+ if (![_appName isNotEmpty]) {
+ [self release];
+ return nil;
+ }
+
+ self->productDirectoryName =
+ [[NSString alloc] initWithFormat:@"%@-%i.%i", _appName, _mav, _miv];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self->productDirectoryName release];
+ [self->searchPathes release];
+ [super dealloc];
+}
+
+/* loading */
+
+- (void)_addCocoaSearchPathesToArray:(NSMutableArray *)ma {
+ id tmp;
+
+ tmp = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory,
+ NSAllDomainsMask,
+ YES);
+ if ([tmp count] > 0) {
+ NSEnumerator *e;
+
+ e = [tmp objectEnumerator];
+ while ((tmp = [e nextObject])) {
+ tmp = [tmp stringByAppendingPathComponent:self->productDirectoryName];
+ if (![ma containsObject:tmp])
+ [ma addObject:tmp];
+ }
+ }
+}
+
+- (void)_addGNUstepSearchPathesToArray:(NSMutableArray *)ma {
+ NSDictionary *env;
+ id tmp;
+
+ env = [[NSProcessInfo processInfo] environment];
+ if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil)
+ tmp = [env objectForKey:@"GNUSTEP_PATHLIST"];
+
+ tmp = [tmp componentsSeparatedByString:@":"];
+ if ([tmp count] > 0) {
+ NSEnumerator *e;
+
+ e = [tmp objectEnumerator];
+ while ((tmp = [e nextObject]) != nil) {
+ tmp = [tmp stringByAppendingPathComponent:@"Library"];
+ tmp = [tmp stringByAppendingPathComponent:self->productDirectoryName];
+ if (![ma containsObject:tmp])
+ [ma addObject:tmp];
+ }
+ }
+ else {
+ [self logWithFormat:@"%s: empty library search path !",
+ __PRETTY_FUNCTION__];
+ }
+}
+
+- (void)_addFHSPathesToArray:(NSMutableArray *)ma {
+ NSString *s;
+
+ s = [self->productDirectoryName lowercaseString];
+ [ma addObject:[@"/usr/local/lib/" stringByAppendingString:s]];
+ [ma addObject:[@"/usr/lib/" stringByAppendingString:s]];
+}
+
+- (NSArray *)productSearchPathes {
+ NSMutableArray *ma;
+ BOOL hasGNUstepEnv;
+
+ if (self->searchPathes != nil)
+ return self->searchPathes;
+
+ hasGNUstepEnv = [[[[NSProcessInfo processInfo] environment]
+ objectForKey:@"GNUSTEP_USER_ROOT"] length] > 0 ? YES : NO;
+
+ ma = [NSMutableArray arrayWithCapacity:6];
+
+ if (hasGNUstepEnv)
+ [self _addGNUstepSearchPathesToArray:ma];
+#if COCOA_Foundation_LIBRARY
+ else
+ [self _addCocoaSearchPathesToArray:ma];
+#endif
+
+ [self _addFHSPathesToArray:ma];
+
+ self->searchPathes = [ma copy];
+
+ if ([self->searchPathes count] == 0) {
+ [self logWithFormat:@"%s: no search pathes were found !",
+ __PRETTY_FUNCTION__];
+ }
+
+ return self->searchPathes;
+}
+
+- (void)loadProducts {
+ SoProductRegistry *registry = nil;
+ NSFileManager *fm;
+ NSEnumerator *pathes;
+ NSString *lpath;
+
+ registry = [SoProductRegistry sharedProductRegistry];
+ fm = [NSFileManager defaultManager];
+
+ pathes = [[self productSearchPathes] objectEnumerator];
+ while ((lpath = [pathes nextObject]) != nil) {
+ NSEnumerator *productNames;
+ NSString *productName;
+
+ [self logWithFormat:@"scanning for products in: %@", lpath];
+
+ productNames = [[fm directoryContentsAtPath:lpath] objectEnumerator];
+
+ while ((productName = [productNames nextObject]) != nil) {
+ NSString *bpath;
+
+ if ([[productName pathExtension] length] == 0)
+ /* filter out directories without extensions */
+ continue;
+
+ bpath = [lpath stringByAppendingPathComponent:productName];
+ [self logWithFormat:@" register product: %@",
+ [bpath lastPathComponent]];
+ [registry registerProductAtPath:bpath];
+ }
+ }
+
+ if (![registry loadAllProducts])
+ [self warnWithFormat:@"could not load all products !"];
+}
+
+@end /* SoProductLoader */