From f169caa814592da007aca0aa10f508793713c20b Mon Sep 17 00:00:00 2001 From: rfm Date: Sat, 5 Mar 2011 07:54:05 +0000 Subject: [PATCH] User defaults language/setup restructuring git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@32454 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 17 + Source/NSBundle.m | 6 +- Source/NSLocale.m | 4 +- Source/NSNumberFormatter.m | 2 +- Source/NSSpellServer.m | 7 +- Source/NSUserDefaults.m | 618 +++++++++++++++++-------------------- 6 files changed, 319 insertions(+), 335 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5dfd052e2..0674ac8aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2011-03-05 Richard Frith-Macdonald + + * Source/NSNumberFormatter.m: Make error text compatible with OSX + * Source/NSSpellServer.m: Use NSLanguages user default + * Source/NSBundle.m: Use NSLanguages user default + * Source/NSUserDefaults.m: + Revert recent attempt to avoid deadlocks (broke thread-safety). + Rewrite shared defaults initialisation and user language management + to break the complicated interrelationshp between methods which + made the initialisation fragile and incomprehensible. + Language information derived from operating system or environment + variables (rather than the defaults database) is now stored in a + new volatile domain. + The +userLanguages method just returns the NSLanguages default, + and +setUserLanguages: now sets NSLanguages in the new volatile domain. + Simplify setup of shared user defaults to avoid deadlocks. + 2011-03-04 Richard Frith-Macdonald * Source/NSOperation.m: retain operation while finishing so that it diff --git a/Source/NSBundle.m b/Source/NSBundle.m index be4ee30ef..cbd65b90e 100644 --- a/Source/NSBundle.m +++ b/Source/NSBundle.m @@ -1685,7 +1685,8 @@ IF_NO_GC( NSEnumerator *enumerate; array = [NSMutableArray arrayWithCapacity: 8]; - languages = [NSUserDefaults userLanguages]; + languages = [[NSUserDefaults standardUserDefaults] + stringArrayForKey: @"NSLanguages"]; primary = [rootPath stringByAppendingPathComponent: @"Resources"]; [array addObject: _bundle_resource_path(primary, subPath, nil)]; @@ -1945,7 +1946,8 @@ IF_NO_GC( + (NSArray *) preferredLocalizationsFromArray: (NSArray *)localizationsArray { return [self preferredLocalizationsFromArray: localizationsArray - forPreferences: [NSUserDefaults userLanguages]]; + forPreferences: [[NSUserDefaults standardUserDefaults] + stringArrayForKey: @"NSLanguages"]]; } + (NSArray *) preferredLocalizationsFromArray: (NSArray *)localizationsArray diff --git a/Source/NSLocale.m b/Source/NSLocale.m index 817dc9457..e00f49b73 100644 --- a/Source/NSLocale.m +++ b/Source/NSLocale.m @@ -543,8 +543,10 @@ static NSRecursiveLock *classLock = nil; NSMutableArray *mArray; NSUInteger cnt; NSUInteger idx = 0; - NSArray *languages = [NSUserDefaults userLanguages]; + NSArray *languages; + languages = [[NSUserDefaults standardUserDefaults] + stringArrayForKey: @"NSLanguages"]; if (languages == nil) return [NSArray arrayWithObject: @"en"]; diff --git a/Source/NSNumberFormatter.m b/Source/NSNumberFormatter.m index f69f84149..6e7150304 100644 --- a/Source/NSNumberFormatter.m +++ b/Source/NSNumberFormatter.m @@ -419,7 +419,7 @@ static NSUInteger _defaultBehavior = NSNumberFormatterBehavior10_4; { if (0 != error) { - *error = _(@"floating point values not allowed"); + *error = _(@"Floating Point not allowed"); } return NO; } diff --git a/Source/NSSpellServer.m b/Source/NSSpellServer.m index 12e4a81c5..16073c052 100644 --- a/Source/NSSpellServer.m +++ b/Source/NSSpellServer.m @@ -81,9 +81,12 @@ GSSpellServerName(NSString *vendor, NSString *language) // Non-private Instance methods - (id) init { - NSArray *userLanguages = [NSUserDefaults userLanguages]; - NSString *currentLanguage = [userLanguages objectAtIndex: 0]; + NSArray *userPreference; + NSString *currentLanguage; + userPreference = [[NSUserDefaults standardUserDefaults] + stringArrayForKey: @"NSLanguages"]; + currentLanguage = [userPreference objectAtIndex: 0]; if ((self = [super init]) != nil) { _delegate = nil; diff --git a/Source/NSUserDefaults.m b/Source/NSUserDefaults.m index affac20bb..6d29c922e 100644 --- a/Source/NSUserDefaults.m +++ b/Source/NSUserDefaults.m @@ -86,14 +86,19 @@ static Class NSNumberClass; static Class NSMutableDictionaryClass; static Class NSStringClass; +static NSString *GSPrimaryDomain = @"GSPrimaryDomain"; static NSString *defaultsFile = @".GNUstepDefaults"; static NSUserDefaults *sharedDefaults = nil; static NSMutableString *processName = nil; -static NSMutableArray *userLanguages = nil; -static BOOL invalidatedLanguages = NO; static NSRecursiveLock *classLock = nil; +/* Flag to say whether the sharedDefaults variable has been set up by a + * call to the +standardUserDefaults method. If this is YES but the variable + * is nil then there was a problem initialising the shared object and we + * have no defaults available. + */ +static BOOL hasSharedDefaults = NO; /* * Caching some defaults. */ @@ -173,6 +178,76 @@ writeDictionary(NSDictionary *dict, NSString *file) return NO; } +static NSMutableArray * +newLanguages(NSArray *oldNames) +{ + NSMutableArray *newNames; + NSEnumerator *enumerator; + NSString *language; + NSString *locale = nil; + +#ifdef HAVE_LOCALE_H +#ifdef LC_MESSAGES + locale = GSSetLocale(LC_MESSAGES, nil); +#endif +#endif + newNames = [NSMutableArray arrayWithCapacity: 5]; + + if (oldNames == nil && locale != nil) + { + NSString *locLang = GSLanguageFromLocale(locale); + + if (nil != locLang) + { + oldNames = [NSArray arrayWithObject: locLang]; + } +#ifdef __MINGW__ + if (oldNames == nil) + { + /* Check for language as the first part of the locale string */ + NSRange under = [locale rangeOfString: @"_"]; + + if (under.location) + { + oldNames = [NSArray arrayWithObject: + [locale substringToIndex: under.location]]; + } + } +#endif + } + if (oldNames == nil) + { + NSString *env; + + env = [[[NSProcessInfo processInfo] environment] + objectForKey: @"LANGUAGES"]; + if (env != nil) + { + oldNames = [env componentsSeparatedByString: @";"]; + } + } + + enumerator = [oldNames objectEnumerator]; + while (nil != (language = [enumerator nextObject])) + { + language = [language stringByTrimmingSpaces]; + if ([language length] > 0 && NO == [newNames containsObject: language]) + { + [newNames addObject: language]; + } + } + + /* Check if "English" is included. We do this to make sure all the + * required language constants are set somewhere if they aren't set + * in the default language. + */ + if (NO == [newNames containsObject: @"English"]) + { + [newNames addObject: @"English"]; + } + return newNames; +} + /************************************************************************* *** Local method definitions *************************************************************************/ @@ -207,6 +282,12 @@ writeDictionary(NSDictionary *dict, NSString *file) * looks through the various domains in a particular order. *

* + * GSPrimaryDomain ... volatile + * + * Contains values set at runtime and intended to supercede any values + * set in other domains. This should be used with great care since it + * overrides values which may have been set explicitly by the user. + * * NSArgumentDomain ... volatile * * Contains defaults read from the arguments provided @@ -220,8 +301,10 @@ writeDictionary(NSDictionary *dict, NSString *file) * * Application (name of the current process) ... persistent * - * Contains application specific defaults, - * such as window positions. + * Contains application specific defaults, such as window positions. + * This is the domain used by the -setObject:forKey: method and is + * the domain normally used when setting preferences for an application. + * * NSGlobalDomain ... persistent * * Global defaults applicable to all applications. @@ -280,8 +363,6 @@ writeDictionary(NSDictionary *dict, NSString *file) */ @implementation NSUserDefaults: NSObject -static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ - + (void) initialize { if (self == [NSUserDefaults class]) @@ -305,12 +386,14 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ + (void) resetStandardUserDefaults { + NSDictionary *regDefs; + [classLock lock]; NS_DURING { - if (sharedDefaults != nil) + regDefs = [sharedDefaults volatileDomainForName: @"NSRegistrationDomain"]; + if (nil != sharedDefaults) { - NSDictionary *regDefs; /* To ensure that we don't try to synchronise the old defaults to disk * after creating the new ones, remove as housekeeping notification @@ -323,22 +406,9 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ */ [sharedDefaults synchronize]; DESTROY(sharedDefaults->_changedDomains); - - regDefs = RETAIN([sharedDefaults->_tempDomains - objectForKey: NSRegistrationDomain]); - setSharedDefaults = NO; DESTROY(sharedDefaults); - if (regDefs != nil) - { - [self standardUserDefaults]; - if (sharedDefaults != nil) - { - [sharedDefaults->_tempDomains setObject: regDefs - forKey: NSRegistrationDomain]; - } - RELEASE(regDefs); - } - } + } + hasSharedDefaults = NO; [classLock unlock]; } NS_HANDLER @@ -347,6 +417,15 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ [localException raise]; } NS_ENDHANDLER + if (nil != regDefs) + { + [self standardUserDefaults]; + if (sharedDefaults != nil) + { + [sharedDefaults->_tempDomains setObject: regDefs + forKey: NSRegistrationDomain]; + } + } } /* Create a locale dictionary when we have absolutely no information @@ -457,109 +536,113 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ + (NSUserDefaults*) standardUserDefaults { + NSUserDefaults *defs; BOOL added_lang, added_locale; + BOOL setup; id lang; + NSArray *nL; NSArray *uL; NSEnumerator *enumerator; - /* - * Calling +standardUserDefaults and +userLanguages is horribly interrelated. - * Messing with the order of assignments and calls within these methods can - * break things very easily ... take care. - * - * If +standardUserDefaults is called first, it sets up initial information - * in sharedDefaults then calls +userLanguages to get language information. - * +userLanguages then calls +standardUserDefaults to read NSLanguages - * and returns the language information. - * +standardUserDefaults then sets up language domains and loads localisation - * information before returning. - * - * If +userLanguages is called first, it calls +standardUserDefaults - * to obtain the NSLanguages array. - * +standardUserDefaults loads basic information initialising the - * sharedDefaults variable, then calls back to +userLanguages to set up - * its search list. - * +userLanguages calls +standardUserDefaults again to get NSLanguages. - * +standardUserDefaults returns the partially initialised sharedDefaults. - * +userLanguages uses this to create and return the user languages. - * +standardUserDefaults uses the languages to update the search list - * and load in localisation information then returns sharedDefaults. - * +userLanguages uses this to rebuild language information and return it. + /* If the shared instance is already available ... return it. */ - - /* Return the sharedDefaults without locking in the simple case. - * We need to lock and check again before CREATING sharedDefaults if it doesn't exist, - * so that two threads can't create it at once (or call resetStandardUserDefaults at - * the same time). - * By not locking here, we avoid a deadlock that can occur between classLock and _lock. */ - if (setSharedDefaults == YES) - { - IF_NO_GC([sharedDefaults retain];) - return AUTORELEASE(sharedDefaults); - } - [classLock lock]; - - /* - * NB. The use of the setSharedDefaults flag ensures that a recursive - * call to this method is quietly suppressed ... so we get a more - * manageable problem. - */ - if (setSharedDefaults == YES) + defs = [sharedDefaults retain]; + setup = hasSharedDefaults; + [classLock unlock]; + if (YES == setup) { - IF_NO_GC([sharedDefaults retain];) - [classLock unlock]; - return AUTORELEASE(sharedDefaults); + return [defs autorelease]; } - setSharedDefaults = YES; - + NS_DURING { - // Create new sharedDefaults (NOTE: Not added to the autorelease pool!) + /* Create new NSUserDefaults (NOTE: Not added to the autorelease pool!) + * NB. The following code avoids deadlocks by creating a minimally + * initialised instance, locking that instance, locking the class-wide + * lock, installing the instance as the new shared defaults, unlocking + * the class wide lock, completing the setup of the instance, and then + * unlocking the instance. This means we already have the shared + * instance locked ourselves at the point when it first becomes + * visible to other threads. + */ #if defined(__MINGW__) { NSString *path = GSDefaultsRootForUser(NSUserName()); - NSRange r = [path rangeOfString: @":REGISTRY:"]; + NSRange r = [path rangeOfString: @":REGISTRY:"]; if (r.length > 0) { - sharedDefaults = [[NSUserDefaultsWin32 alloc] init]; + defs = [[NSUserDefaultsWin32 alloc] init]; } else { - sharedDefaults = [[self alloc] init]; + defs = [[self alloc] init]; } } #else - sharedDefaults = [[self alloc] init]; + defs = [[self alloc] init]; #endif - if (sharedDefaults == nil) - { - NSLog(@"WARNING - unable to create shared user defaults!\n"); - [classLock unlock]; - NS_VALRETURN(nil); - } + + /* Install the new defaults as the shared copy, but lock it so that + * we can complete setup without other threads interfering. + */ + if (nil != defs) + { + [defs->_lock lock]; + [classLock lock]; + if (NO == hasSharedDefaults) + { + hasSharedDefaults = YES; + sharedDefaults = [defs retain]; + } + else + { + /* Already set up by another thread. + */ + [defs->_lock unlock]; + [defs release]; + defs = nil; + } + [classLock unlock]; + } + + if (nil == defs) + { + NSLog(@"WARNING - unable to create shared user defaults!\n"); + NS_VALRETURN(nil); + } /* * Set up search list (excluding language list, which we don't know yet) */ - [sharedDefaults->_searchList addObject: NSArgumentDomain]; - [sharedDefaults->_searchList addObject: processName]; - [sharedDefaults->_searchList addObject: NSGlobalDomain]; - [sharedDefaults->_searchList addObject: GSConfigDomain]; - [sharedDefaults->_searchList addObject: NSRegistrationDomain]; + [defs->_searchList addObject: GSPrimaryDomain]; + [defs->_searchList addObject: NSArgumentDomain]; + [defs->_searchList addObject: processName]; + [defs->_searchList addObject: NSGlobalDomain]; + [defs->_searchList addObject: GSConfigDomain]; + [defs->_searchList addObject: NSRegistrationDomain]; + + /* Load persistent data into the new instance. + */ + [defs synchronize]; /* * Look up user languages list and insert language specific domains * into search list before NSRegistrationDomain */ - uL = [self userLanguages]; - enumerator = [uL objectEnumerator]; + uL = [defs stringArrayForKey: @"NSLanguages"]; + nL = newLanguages(uL); + if (NO == [uL isEqual: nL]) + { + [self setUserLanguages: nL]; + } + enumerator = [nL objectEnumerator]; while ((lang = [enumerator nextObject])) { - unsigned index = [sharedDefaults->_searchList count] - 1; + unsigned index = [defs->_searchList count] - 1; - [sharedDefaults->_searchList insertObject: lang atIndex: index]; + [defs->_searchList insertObject: lang atIndex: index]; } /* Set up language constants */ @@ -623,7 +706,7 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ } if (dict != nil) { - [sharedDefaults setVolatileDomain: dict forName: lang]; + [defs setVolatileDomain: dict forName: lang]; added_lang = YES; } else if (added_locale == NO) @@ -663,8 +746,7 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ dict = GSDomainFromDefaultLocale (); if (dict != nil) { - [sharedDefaults setVolatileDomain: dict - forName: lang]; + [defs setVolatileDomain: dict forName: lang]; /* We do not set added_lang to YES here * because we want the basic hardcoded defaults @@ -684,154 +766,49 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ * We need to use hard-coded defaults. */ /* FIXME - should we set this as volatile domain for English ? */ - [sharedDefaults registerDefaults: [self _unlocalizedDefaults]]; + [defs registerDefaults: [self _unlocalizedDefaults]]; } - IF_NO_GC([sharedDefaults retain];) updateCache(sharedDefaults); - [classLock unlock]; + [defs->_lock unlock]; } NS_HANDLER { - [classLock unlock]; + [defs->_lock unlock]; + [defs release]; [localException raise]; } NS_ENDHANDLER - return AUTORELEASE(sharedDefaults); + return [defs autorelease]; } + (NSArray*) userLanguages { - NSArray *result = nil; - - /* - * Calling +standardUserDefaults and +userLanguages is horribly interrelated. - * Messing with the order of assignments and calls within these methods can - * break things very easily ... take care. - * - * If +standardUserDefaults is called first, it sets up initial information - * in sharedDefaults then calls +userLanguages to get language information. - * +userLanguages then calls +standardUserDefaults to read NSLanguages - * and returns the language information. - * +standardUserDefaults then sets up language domains and loads localisation - * information before returning. - * - * If +userLanguages is called first, it calls +standardUserDefaults - * to obtain the NSLanguages array. - * +standardUserDefaults loads basic information initialising the - * sharedDefaults variable, then calls back to +userLanguages to set up - * its search list. - * +userLanguages calls +standardUserDefaults again to get NSLanguages. - * +standardUserDefaults returns the partially initialised sharedDefaults. - * +userLanguages uses this to create and return the user languages. - * +standardUserDefaults uses the languages to update the search list - * and load in localisation information then returns sharedDefaults. - * +userLanguages uses this to rebuild language information and return it. - */ - - [classLock lock]; - NS_DURING - { - if (invalidatedLanguages == YES) - { - invalidatedLanguages = NO; - DESTROY(userLanguages); - } - if (userLanguages == nil) - { - NSArray *currLang = nil; - NSString *locale = nil; - -#ifdef HAVE_LOCALE_H -#ifdef LC_MESSAGES - locale = GSSetLocale(LC_MESSAGES, nil); -#endif -#endif - currLang = [[NSUserDefaults standardUserDefaults] - stringArrayForKey: @"NSLanguages"]; - - userLanguages = [[NSMutableArray alloc] initWithCapacity: 5]; - - if (currLang == nil && locale != nil && GSLanguageFromLocale(locale)) - { - currLang = [NSArray arrayWithObject: GSLanguageFromLocale(locale)]; - } -#ifdef __MINGW__ - if (currLang == nil && locale != nil) - { - /* Check for language as the first part of the locale string */ - NSRange under = [locale rangeOfString: @"_"]; - if (under.location) - currLang = [NSArray arrayWithObject: - [locale substringToIndex: under.location]]; - } -#endif - if (currLang == nil) - { - NSString *env; - - env = [[[NSProcessInfo processInfo] environment] - objectForKey: @"LANGUAGES"]; - if (env != nil) - { - currLang = [env componentsSeparatedByString: @";"]; - } - } - - if (currLang != nil) - { - NSMutableArray *a = [currLang mutableCopy]; - unsigned c = [a count]; - - while (c-- > 0) - { - NSString *s = [[a objectAtIndex: c] stringByTrimmingSpaces]; - - if ([s length] == 0) - { - [a removeObjectAtIndex: c]; - } - else - { - [a replaceObjectAtIndex: c withObject: s]; - } - } - [userLanguages addObjectsFromArray: a]; - RELEASE(a); - } - - /* Check if "English" is included. We do this to make sure all the - required language constants are set somewhere if they aren't set - in the default language */ - if ([userLanguages containsObject: @"English"] == NO) - { - [userLanguages addObject: @"English"]; - } - } - result = RETAIN(userLanguages); - [classLock unlock]; - } - NS_HANDLER - { - [classLock unlock]; - [localException raise]; - } - NS_ENDHANDLER - return AUTORELEASE(result); + return [[NSUserDefaults standardUserDefaults] + stringArrayForKey: @"NSLanguages"]; } + (void) setUserLanguages: (NSArray*)languages { - NSMutableDictionary *globDict; + NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; + NSMutableDictionary *dict; - globDict = [[[self standardUserDefaults] - persistentDomainForName: NSGlobalDomain] mutableCopy]; + dict = [[defs volatileDomainForName: GSPrimaryDomain] mutableCopy]; if (languages == nil) // Remove the entry - [globDict removeObjectForKey: @"NSLanguages"]; + { + [dict removeObjectForKey: @"NSLanguages"]; + } else - [globDict setObject: languages forKey: @"NSLanguages"]; - [[self standardUserDefaults] - setPersistentDomain: globDict forName: NSGlobalDomain]; - RELEASE(globDict); + { + if (nil == dict) + { + dict = [NSMutableDictionary new]; + } + languages = newLanguages(languages); + [dict setObject: languages forKey: @"NSLanguages"]; + } + [defs removeVolatileDomainForName: GSPrimaryDomain]; + [defs setVolatileDomain: dict forName: GSPrimaryDomain]; + [dict release]; } - (id) init @@ -918,27 +895,6 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ { // Initialize _persDomains from the archived user defaults (persistent) _persDomains = [[NSMutableDictionaryClass alloc] initWithCapacity: 10]; - if ([self synchronize] == NO) - { - DESTROY(self); - return self; - } - } - - // Check and if not existent add the Application and the Global domains - if ([_persDomains objectForKey: processName] == nil) - { - [_persDomains - setObject: [NSMutableDictionaryClass dictionaryWithCapacity: 10] - forKey: processName]; - [self __changePersistentDomain: processName]; - } - if ([_persDomains objectForKey: NSGlobalDomain] == nil) - { - [_persDomains - setObject: [NSMutableDictionaryClass dictionaryWithCapacity: 10] - forKey: NSGlobalDomain]; - [self __changePersistentDomain: NSGlobalDomain]; } // Create volatile defaults and add the Argument and the Registration domains @@ -1007,7 +963,6 @@ static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */ NS_DURING { DESTROY(_dictionaryRep); - if (self == sharedDefaults) invalidatedLanguages = YES; [_searchList removeObject: aName]; index = [_searchList indexOfObject: processName]; index = (index == NSNotFound) ? 0 : (index + 1); @@ -1357,7 +1312,6 @@ static BOOL isPlistObject(id o) NS_DURING { DESTROY(_dictionaryRep); - if (self == sharedDefaults) invalidatedLanguages = YES; RELEASE(_searchList); _searchList = [newList mutableCopy]; [_lock unlock]; @@ -1705,107 +1659,118 @@ NSLog(@"Creating empty user defaults database"); - (BOOL) synchronize { NSMutableDictionary *newDict; + NSDate *saved; BOOL wasLocked; + BOOL result = YES; [_lock lock]; + saved = _lastSync; + _lastSync = [NSDate new]; // Record timestamp of this sync. NS_DURING { /* * If we haven't changed anything, we only need to synchronise if * the on-disk database has been changed by someone else. */ - - if (_changedDomains == nil) - { - if ([self wantToReadDefaultsSince: _lastSync] == NO) + if (_changedDomains != nil + || YES == [self wantToReadDefaultsSince: saved]) + { + DESTROY(_dictionaryRep); + if ([self lockDefaultsFile: &wasLocked] == NO) { - [_lock unlock]; - NS_VALRETURN(YES); + result = NO; } - } + else if (nil == (newDict = [self readDefaults])) + { + if (wasLocked == NO) + { + [self unlockDefaultsFile]; + } + result = NO; + } + else if (_changedDomains != nil) + { // Synchronize both dictionaries + NSEnumerator *enumerator; + NSString *domainName; + NSDictionary *domain; + NSDictionary *oldData = AUTORELEASE([newDict copy]); - DESTROY(_dictionaryRep); - if (self == sharedDefaults) - { - invalidatedLanguages = YES; - } - - if ([self lockDefaultsFile: &wasLocked] == NO) - { - [_lock unlock]; - NS_VALRETURN(NO); - } - - newDict = [self readDefaults]; - - if (newDict == nil) - { - if (wasLocked == NO) + enumerator = [_changedDomains objectEnumerator]; + DESTROY(_changedDomains); // Retained by enumerator. + while ((domainName = [enumerator nextObject]) != nil) + { + domain = [_persDomains objectForKey: domainName]; + if (domain != nil) // Domain was added or changed + { + [newDict setObject: domain forKey: domainName]; + } + else // Domain was removed + { + [newDict removeObjectForKey: domainName]; + } + } + ASSIGN(_persDomains, newDict); + if ([self writeDefaults: _persDomains oldData: oldData] == NO) + { + if (wasLocked == NO) + { + [self unlockDefaultsFile]; + } + result = NO; + } + } + else + { + if ([_persDomains isEqual: newDict] == NO) + { + ASSIGN(_persDomains, newDict); + updateCache(self); + [[NSNotificationCenter defaultCenter] + postNotificationName: NSUserDefaultsDidChangeNotification + object: self]; + } + } + if (wasLocked == NO) { [self unlockDefaultsFile]; } - [_lock unlock]; - NS_VALRETURN(NO); - } - - if (_changedDomains != nil) - { // Synchronize both dictionaries - NSEnumerator *enumerator = [_changedDomains objectEnumerator]; - NSString *domainName; - NSDictionary *domain; - NSDictionary *oldData = AUTORELEASE([newDict copy]); - - DESTROY(_changedDomains); // Retained by enumerator. - while ((domainName = [enumerator nextObject]) != nil) - { - domain = [_persDomains objectForKey: domainName]; - if (domain != nil) // Domain was added or changed - { - [newDict setObject: domain forKey: domainName]; - } - else // Domain was removed - { - [newDict removeObjectForKey: domainName]; - } - } - ASSIGN(_persDomains, newDict); - if ([self writeDefaults: _persDomains oldData: oldData] == NO) - { - if (wasLocked == NO) - { - [self unlockDefaultsFile]; - } - [_lock unlock]; - NS_VALRETURN(NO); - } - ASSIGN(_lastSync, [NSDateClass date]); - } - else - { - ASSIGN(_lastSync, [NSDateClass date]); - if ([_persDomains isEqual: newDict] == NO) - { - ASSIGN(_persDomains, newDict); - updateCache(self); - [[NSNotificationCenter defaultCenter] - postNotificationName: NSUserDefaultsDidChangeNotification - object: self]; - } - } - - if (wasLocked == NO) - { - [self unlockDefaultsFile]; - } - [_lock unlock]; + } } NS_HANDLER { + [_lastSync release]; + _lastSync = saved; [_lock unlock]; [localException raise]; } NS_ENDHANDLER - return YES; + + if (YES == result) + { + [saved release]; + } + else + { + [_lastSync release]; + _lastSync = saved; + } + // Check and if not existent add the Application and the Global domains + if ([_persDomains objectForKey: processName] == nil) + { + [_persDomains + setObject: [NSMutableDictionaryClass dictionaryWithCapacity: 10] + forKey: processName]; + [self __changePersistentDomain: processName]; + } + if ([_persDomains objectForKey: NSGlobalDomain] == nil) + { + [_persDomains + setObject: [NSMutableDictionaryClass dictionaryWithCapacity: 10] + forKey: NSGlobalDomain]; + [self __changePersistentDomain: NSGlobalDomain]; + } + [_lock unlock]; + return result; } @@ -1815,7 +1780,6 @@ NSLog(@"Creating empty user defaults database"); NS_DURING { DESTROY(_dictionaryRep); - if (self == sharedDefaults) invalidatedLanguages = YES; [_tempDomains removeObjectForKey: domainName]; [_lock unlock]; } @@ -1849,7 +1813,6 @@ NSLog(@"Creating empty user defaults database"); } DESTROY(_dictionaryRep); - if (self == sharedDefaults) invalidatedLanguages = YES; domain = [domain mutableCopy]; [_tempDomains setObject: domain forKey: domainName]; RELEASE(domain); @@ -1968,7 +1931,6 @@ NSLog(@"Creating empty user defaults database"); [_tempDomains setObject: regDefs forKey: NSRegistrationDomain]; } DESTROY(_dictionaryRep); - if (self == sharedDefaults) invalidatedLanguages = YES; [regDefs addEntriesFromDictionary: newVals]; [_lock unlock]; } @@ -1991,7 +1953,6 @@ NSLog(@"Creating empty user defaults database"); NS_DURING { DESTROY(_dictionaryRep); - if (self == sharedDefaults) invalidatedLanguages = YES; [_searchList removeObject: aName]; [_lock unlock]; } @@ -2111,7 +2072,6 @@ NSLog(@"Creating empty user defaults database"); NS_DURING { DESTROY(_dictionaryRep); - if (self == sharedDefaults) invalidatedLanguages = YES; if (_changedDomains == nil) { _changedDomains = [[NSMutableArray alloc] initWithObjects: &domainName