This is NSUserDefaults.m in view mode; [Download] [Up]
/* NSUserDefaults.m Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea. All rights reserved. Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro> This file is part of libFoundation. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. We disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness, in no event shall we be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. */ #include <Foundation/common.h> #include <Foundation/NSString.h> #include <Foundation/NSData.h> #include <Foundation/NSValue.h> #include <Foundation/NSArray.h> #include <Foundation/NSDictionary.h> #include <Foundation/NSDate.h> #include <Foundation/NSNotification.h> #include <Foundation/NSProcessInfo.h> #include <Foundation/NSDistributedLock.h> #include <Foundation/NSBundle.h> #include <Foundation/NSUserDefaults.h> #include <Foundation/NSFileManager.h> #include <Foundation/exceptions/GeneralExceptions.h> /* * User defaults strings */ /* Defaults Domains */ NSString* NSArgumentDomain = @"NSArgumentDomain"; NSString* NSGlobalDomain = @"NSGlobalDomain"; NSString* NSRegistrationDomain = @"NSRegistrationDomain"; /* Notification name */ NSString* NSUserDefaultsDidChangeNotification = @"NSUserDefaultsDidChangeNotification"; /* Defaults names */ NSString* NSWeekDayNameArray = @"NSWeekDayNameArray"; NSString* NSShortWeekDayNameArray = @"NSShortWeekDayNameArray"; NSString* NSMonthNameArray = @"NSMonthNameArray"; NSString* NSShortMonthNameArray = @"NSShortMonthNameArray"; NSString* NSTimeFormatString = @"NSTimeFormatString"; NSString* NSDateFormatString = @"NSDateFormatString"; NSString* NSTimeDateFormatString = @"NSTimeDateFormatString"; NSString* NSShortTimeDateFormatString = @"NSShortTimeDateFormatString"; NSString* NSCurrencySymbol = @"NSCurrencySymbol"; NSString* NSDecimalSeparator = @"NSDecimalSeparator"; NSString* NSThousandsSeparator = @"NSThousandsSeparator"; NSString* NSInternationalCurrencyString = @"NSInternationalCurrencyString"; NSString* NSCurrencyString = @"NSCurrencyString"; NSString* NSDecimalDigits = @"NSDecimalDigits"; NSString* NSAMPMDesignation = @"NSAMPMDesignation"; /* * User defaults shared class */ @interface NSSharedUserDefaults : NSUserDefaults @end @implementation NSSharedUserDefaults - retain {return self;} - autorelease {return self;} - (void)release{} - (unsigned int)retainCount {return 1;} @end /* * User defaults class */ @implementation NSUserDefaults : NSObject /* Getting and Setting a Default */ - (NSArray*)arrayForKey:(NSString*)defaultName { id obj = [self objectForKey:defaultName]; if ([obj isKindOfClass:[NSArray class]]) return obj; return nil; } - (NSDictionary*)dictionaryForKey:(NSString*)defaultName { id obj = [self objectForKey:defaultName]; if ([obj isKindOfClass:[NSDictionary class]]) return obj; return nil; } - (NSData*)dataForKey:(NSString*)defaultName; { id obj = [self objectForKey:defaultName]; if ([obj isKindOfClass:[NSData class]]) return obj; return nil; } - (NSArray*)stringArrayForKey:(NSString*)defaultName { id obj = [self objectForKey:defaultName]; if ([obj isKindOfClass:[NSArray class]]) { int n; Class strClass = [NSString class]; for (n = [obj count]-1; n >= 0; n--) if (![[obj objectAtIndex:n] isKindOfClass:strClass]) return nil; return obj; } return nil; } - (NSString*)stringForKey:(NSString*)defaultName { id obj = [self objectForKey:defaultName]; if ([obj isKindOfClass:[NSString class]]) return obj; return nil; } - (BOOL)boolForKey:(NSString*)defaultName { id obj = [self objectForKey:defaultName]; if (obj && [obj isKindOfClass:[NSString class]]) { if ([obj compare:@"YES" options:NSCaseInsensitiveSearch] == NSOrderedSame) return YES; else if ([obj respondsToSelector:@selector(intValue)]) return [obj intValue] ? YES : NO; } return NO; } - (float)floatForKey:(NSString*)defaultName { id obj = [self stringForKey:defaultName]; if (obj) return [obj floatValue]; return 0; } - (int)integerForKey:(NSString*)defaultName { id obj = [self stringForKey:defaultName]; if (obj) return [obj intValue]; return 0; } - (void)setBool:(BOOL)value forKey:(NSString*)defaultName { [self setObject:(value ? @"YES" : @"NO") forKey:defaultName]; } - (void)setFloat:(float)value forKey:(NSString*)defaultName { [self setObject:[NSString stringWithFormat:@"%f", value] forKey:defaultName]; } - (void)setInteger:(int)value forKey:(NSString*)defaultName { [self setObject:[NSString stringWithFormat:@"%d", value] forKey:defaultName]; } /* Accessing app domain defaults */ - (id)objectForKey:(NSString*)defaultName { int i, n = [searchList count]; for (i=0; i<n; i++) { NSString* name = [searchList objectAtIndex:i]; NSDictionary* domain; id obj; if ((domain = [volatileDomains objectForKey:name])) if ((obj = [domain objectForKey:defaultName])) return obj; if ((domain = [persistentDomains objectForKey:name])) if ((obj = [domain objectForKey:defaultName])) return obj; } return nil; } - (void)setObject:(id)value forKey:(NSString*)defaultName { [(NSMutableDictionary*)[self persistentDomainForName:appDomain] setObject:value forKey:defaultName]; [self persistentDomainHasChanged:appDomain]; } - (void)removeObjectForKey:(NSString*)defaultName { [(NSMutableDictionary*)[self persistentDomainForName:appDomain] removeObjectForKey:defaultName]; [self persistentDomainHasChanged:appDomain]; } /* Returning the Search List */ - (NSMutableArray*)searchList { return searchList; } /* Making Advanced Use of Defaults */ - (NSDictionary*)dictionaryRepresentation { NSMutableDictionary* dict = [[NSMutableDictionary new] autorelease]; int i, n = [searchList count]; for (i = n-1; i >= 0; i--) { NSString* name = [searchList objectAtIndex:i]; NSDictionary* domain; if ((domain = [volatileDomains objectForKey:name])) [dict addEntriesFromDictionary:domain]; if ((domain = [persistentDomains objectForKey:name])) [dict addEntriesFromDictionary:domain]; } return dict; } - (void)registerDefaults:(NSDictionary*)dictionary { NSMutableDictionary* regDomain = [self volatileDomainForName:NSRegistrationDomain]; if ([searchList indexOfObjectIdenticalTo:regDomain] == NSNotFound) [searchList addObject:NSRegistrationDomain]; [regDomain addEntriesFromDictionary:dictionary]; } /* Maintaining Volatile Domains */ - (void)removeVolatileDomainForName:(NSString*)domainName { [searchList removeObject:domainName]; [volatileDomains removeObjectForKey:domainName]; } - (void)setVolatileDomain:(NSDictionary*)domain forName:(NSString*)domainName { if ([volatileDomains objectForKey:domainName]) THROW([[InvalidArgumentException alloc] initWithFormat:@"volatile domain %@ already exists", domainName]); [volatileDomains setObject: [[NSMutableDictionary alloc] initWithDictionary:domain] forKey:domainName]; } - (NSDictionary*)volatileDomainForName:(NSString*)domainName { return [volatileDomains objectForKey:domainName]; } - (NSArray*)volatileDomainNames { return [volatileDomains allKeys]; } /* Maintaining Persistent Domains */ - (NSDictionary*)loadPersistentDomainNamed:(NSString*)domainName { int n; NSDistributedLock* lock = nil; NSDictionary* dict = nil; NSString* domainPath; NSString* path; /* Declare here `format' to work around a bug in compiler */ NSString* format = @"caught exception %@ with reason %@ " @"while loading user defaults domain %@"; domainPath = [[directoryForSaving stringByAppendingPathComponent:domainName] stringByAppendingPathExtension:@"plist"]; /* Take the address of `path' to force the compiler to not allocate it in a register. */ *(&path) = [domainPath stringByResolvingSymlinksInPath]; // if (!domainName || [domainName isEqual:@""] || !path) { // NSLog(@"could not load user defaults domain %@ from path %@", // domainName, domainPath); // } if (path) { lock = [NSDistributedLock lockWithPath: [[path stringByDeletingPathExtension] stringByAppendingPathExtension:@"lock"]]; for (n = 0; n < 3; n++) if ([lock tryLock]) break; else sleep(1); if (n >= 3) { NSLog(@"could not lock user defaults domain %@", domainName); return nil; } TRY { dict = [[NSString stringWithContentsOfFile:path] propertyList]; } END_TRY OTHERWISE { NSLog(format, [localException name], [localException reason]); dict = nil; } END_CATCH [lock unlock]; } if (path == nil || dict == nil) { domainPath = [[[[NSBundle libraryResourceDirectory] stringByAppendingPathComponent:@"Defaults"] stringByAppendingPathComponent:domainName] stringByAppendingPathExtension:@"plist"]; path = [domainPath stringByResolvingSymlinksInPath]; if (path) { TRY { dict = [[NSString stringWithContentsOfFile:path] propertyList]; } END_TRY OTHERWISE { NSLog(format, [localException name], [localException reason]); dict = nil; } END_CATCH } // else // NSLog(@"could not load user defaults domain %@ from path %@", // domainName, domainPath); } if (dict == nil) return nil; return [[NSMutableDictionary alloc] initWithDictionary:dict]; } - (BOOL)savePersistentDomainNamed:(NSString*)domainName { int n; BOOL ok = YES; NSDistributedLock* lock = nil; NSDictionary* dict = [persistentDomains objectForKey:domainName]; NSString* path = [[directoryForSaving stringByAppendingPathComponent:domainName] stringByAppendingPathExtension:@"plist"]; /* Declare here `format' to work around a bug in compiler */ NSString* format = @"caught exception %@ with reason %@ " @"while saving user defaults domain %@"; lock = [NSDistributedLock lockWithPath: [path stringByAppendingPathExtension:@"lock"]]; for (n = 0; n < 3; n++) if (![lock tryLock]) sleep(1); else break; if (n >= 3) { NSLog(@"could not lock user defaults domain %@", domainName); return NO; } TRY { ok = [dict writeToFile:path atomically:YES]; } END_TRY OTHERWISE { NSLog(format, [localException name], [localException reason]); ok = NO; } END_CATCH [lock unlock]; return ok; } - (void)removePersistentDomainForName:(NSString*)domainName { [persistentDomains removeObjectForKey:domainName]; } - (NSDictionary*)persistentDomainForName:(NSString*)domainName { NSDictionary* domain; domain = [persistentDomains objectForKey:domainName]; if (!domain) { domain = [self loadPersistentDomainNamed:domainName]; if (domain) [persistentDomains setObject:domain forKey:domainName]; } return domain; } - (void)setPersistentDomain:(NSDictionary*)domain forName:(NSString*)domainName { if ([persistentDomains objectForKey:domainName]) THROW([[InvalidArgumentException alloc] initWithFormat:@"persistent domain %@ already exists", domainName]); [persistentDomains setObject: [[NSMutableDictionary alloc] initWithDictionary:domain] forKey:domainName]; [self persistentDomainHasChanged:domainName]; } - (NSArray*)persistentDomainNames { return [persistentDomains allKeys]; } /* Creation of defaults */ static NSUserDefaults* sharedDefaults = nil; static NSString* sharedDefaultsDir = nil; + (void)setStandardDefaultsDirectory:(NSString*)dir { [dir retain]; [sharedDefaultsDir release]; sharedDefaultsDir = dir; } + (NSUserDefaults*)standardUserDefaults { if (!sharedDefaults) { if (sharedDefaultsDir) sharedDefaults = (id)[[NSSharedUserDefaults alloc] initWithPath:sharedDefaultsDir]; else { NSString* defdir = [[NSHomeDirectoryForUser(NSUserName()) stringByAppendingPathComponent:@".libFoundation"] stringByAppendingPathComponent:@"Defaults"]; if ([defdir stringByResolvingSymlinksInPath] == nil) [[NSFileManager defaultManager] createDirectoryAtPath:defdir attributes:nil]; sharedDefaults = (id)[[NSSharedUserDefaults alloc] initWithPath:defdir]; } [sharedDefaults makeStandardDomainSearchList]; } return sharedDefaults; } + (void)sycronizeStandardUserDefaults:sender { [sharedDefaults synchronize]; } /* Initializing the User Defaults */ - (id)init { return [self initWithUser:NSUserName()]; } - (id)initWithUser:(NSString*)aUserName { return [self initWithPath:[[NSHomeDirectoryForUser(aUserName) stringByAppendingPathComponent:@".libFoundation"] stringByAppendingPathComponent:@"Defaults"]]; } - (id)initWithPath:(NSString*)pathName { NSDictionary* dict; NSArray* languages; int i, n; directoryForSaving = [pathName retain]; persistentDomains = [NSMutableDictionary new]; volatileDomains = [NSMutableDictionary new]; searchList = [NSMutableArray new]; appDomain = [[NSProcessInfo processInfo] processName]; [self setVolatileDomain:[[NSDictionary new] autorelease] forName:NSArgumentDomain]; [self setVolatileDomain:[[NSDictionary new] autorelease] forName:NSRegistrationDomain]; dict = [self persistentDomainForName:appDomain]; if (!dict) [self setPersistentDomain:[[NSDictionary new] autorelease] forName:appDomain]; dict = [self persistentDomainForName:NSGlobalDomain]; if (!dict) [self setPersistentDomain:[[NSDictionary new] autorelease] forName:NSGlobalDomain]; languages = [[self persistentDomainForName:NSGlobalDomain] objectForKey:@"Languages"]; for (i = 0, n = [languages count]; i < n; i++) { dict = [self persistentDomainForName:[languages objectAtIndex:i]]; if (dict) break; } dirty = NO; return self; } - (void)dealloc { [directoryForSaving release]; [appDomain release]; [persistentDomains release]; [volatileDomains release]; [searchList release]; [super dealloc]; } - (void)makeStandardDomainSearchList { int i,n; NSArray* languages; /* make clear list */ [searchList removeAllObjects]; /* make argument domain */ [searchList addObject:NSArgumentDomain]; /* make app domain */ [searchList addObject:appDomain]; /* make global domain */ [searchList addObject:NSGlobalDomain]; /* add languages domains */ languages = [[self persistentDomainForName:NSGlobalDomain] objectForKey:@"Languages"]; if (!languages) { languages = [NSArray arrayWithObject:@"English"]; } for (i = 0, n = [languages count]; i < n; i++) { NSString* lang = [languages objectAtIndex:i]; /* check that the domain exists */ if ([self persistentDomainForName:lang]) { [searchList addObject:lang]; } } /* add catch-all registration domain */ [searchList addObject:NSRegistrationDomain]; } - (BOOL)synchronize { NSEnumerator* penum = [persistentDomains keyEnumerator]; NSString* pname; NSMutableDictionary* pdomain; NSDictionary* ndomain; BOOL allOk = YES; if (!dirty) return YES; while ((pname = [penum nextObject])) { pdomain = [persistentDomains objectForKey:pname]; ndomain = [self loadPersistentDomainNamed:pname]; if (!ndomain || ![ndomain isEqual:pdomain]) { NSEnumerator* nenum = [ndomain keyEnumerator]; NSString* key; while ((key = [nenum nextObject])) { if (![pdomain objectForKey:key]) [pdomain setObject:[ndomain objectForKey:key] forKey:key]; } allOk = [self savePersistentDomainNamed:pname]; } } dirty = NO; return allOk; } - (void)persistentDomainHasChanged:(NSString*)domainName { if (!dirty && [persistentDomains objectForKey:domainName]) { dirty = YES; [[NSNotificationCenter defaultCenter] postNotificationName:NSUserDefaultsDidChangeNotification object:self userInfo:nil]; } } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.